Рамда: Как изменить только одно значение объекта, основываясь на других значениях объекта - PullRequest
0 голосов
/ 25 апреля 2019

Я создаю приложение React. Я использую Ramda, чтобы помочь мне с функциональным программированием.

Если вы хотите увидеть полный код, я также попросил помощи по StackExchange Code Review .

Для переполнения стека важна только одна часть.

Как вы можете изменить конкретное значение из объекта на основе других значений объекта с помощью Рамды? Я использую mapObjIndexed, который в процессе отображается на все ключи.

Контекст: У меня есть объект, представляющий контакт с несколькими ключами, которые являются строками. У объекта всегда есть ключ с именем contactDetails. Я хочу вычислить значение contactDetails в зависимости от значений клавиш tel, bday и email объекта.

Если контакт выглядит так перед функцией:

{
  firstName: 'John',
  lastName: 'Doe',
  contactDetails: '',
  tel: '555-55-5555',
  bday: '',
  email: 'john@doe.com'
}

потом должно выглядеть так:

{
  firstName: 'John',
  lastName: 'Doe',
  contactDetails: 'john@doe.com 555-55-5555',
  tel: '555-55-5555',
  bday: '',
  email: 'john@doe.com'
}

Функция, которую я написал для этого, выглядит следующим образом:

R.mapObjIndexed((val, key, obj) =>
  key === 'contactDetails'
    ? R.trim(
        R.replace(
          /undefined/g,
          '',
          `${R.prop('bday')(obj)} ${R.prop('tel')(obj)} ${R.prop('email')(
            obj
          )}`
        )
      )
    : val
),

Как видите, это довольно грязный и хакерский способ злоупотребления map. Есть ли лучший способ изменить значение объекта в Рамде на основе других значений объекта?

Ответы [ 3 ]

3 голосов
/ 25 апреля 2019

Если это не упражнение в изучении Рамды, я бы предположил, что более простой метод, чем то, что вы, вероятно, придумаете из Рамды, - это простой подход к деструктуризации объектов:

const transform = ({tel, bday, email, ...rest}) => ({
  ...rest, tel, bday, email,
  contactDetails: [bday, email, tel].join(' ').trim()
})

const obj = {firstName: 'John', lastName: 'Doe', tel: '555-55-5555', bday: '', email: 'john@doe.com'}

console.log(transform(obj))

Эта версия не зависит от того, присутствует ли ключ contactDetails, хотя он не повредит, если он там есть.

Если вы 'Вы действительно беспокоитесь о возможном двойном пробеле между словами (например, если указаны bday и tel, но email пусто), вы можете изменить его следующим образом:

const combine = (ss) => ss.reduce((a, s) => a + (s.length ? ' ' : '') + s, '').trim()

const transform = ({tel, bday, email, ...rest}) => ({
  ...rest, tel, bday, email,
  contactDetails: combine([bday, email, tel])
})

Я один из основателей Ramda и большой поклонник, но это всего лишь инструментарий.Есть много мест, где это помогает сделать ваш код легче читать и писать;во что бы то ни стало используйте это тогда.Но когда этого не происходит, даже в кодовой базе, интенсивно использующей Ramda, пропустите ее и используйте другие методы.

2 голосов
/ 25 апреля 2019

В качестве альтернативы ответу Ори мы можем обновить свойство, используя R.assoc('contactDetails'), создав список желаемых значений свойств, используя R.juxt и R.propOr(''), чтобы по умолчанию отсутствовали любые свойства, отклоняя все пустые строки перед их объединением. с R.join.

// takes a list of property names, returning a function that accepts an object
// and produces a list of the values of the provided properties, defaulting to
// an empty string if null or undefined.
const defProps =
  R.compose(R.juxt, R.map(R.propOr('')))

const fn =
  // When `g` is a function, `R.chain(f, g)(x)` is equivalent to `f(g(x), x)`
  R.chain(
    R.assoc('contactDetails'),
    R.pipe(
      defProps(['bday', 'tel', 'email']),
      R.reject(R.equals('')),
      R.join(' ')))

console.log(fn({
  firstName: 'John',
  lastName: 'Doe',
  contactDetails: '',
  tel: '555-55-5555',
  bday: '',
  email: 'john@doe.com'
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
1 голос
/ 25 апреля 2019

Вы можете использовать R.converge для слияния исходного объекта и результата R.pipe, который генерирует свойство contactDetails.Канал получает массив значений через R.props, отфильтровывает ложные значения (неопределенные, пустые строки, пустые значения и т. Д.), Соединяет элементы с пробелами и оборачивает значение объектом с помощью R.objOf.

const { converge, merge, identity, pipe, props, filter, join, trim, objOf } = R

const fn = converge(merge, [identity, pipe(
  props(['bday', 'tel', 'email']),
  filter(Boolean),
  join(' '),
  objOf('contactDetails')
)])

const obj = {
  firstName: 'John',
  lastName: 'Doe',
  contactDetails: '',
  tel: '555-55-5555',
  bday: '',
  email: 'john@doe.com'
}

const result = fn(obj)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
...