Фильтровать базу объектов по массиву с помощью Ramda.js - PullRequest
0 голосов
/ 08 марта 2019
let obj = {
  tom: {
    id: 0
  },
  david: {
    id: 1
  },
  john: {
    id: 2
  }
}

let ids = [1, 2]

Я хочу отфильтровать объект на основе идентификаторов.

Я хочу получить результат

{david: {id: 1}, john: {id: 2}}

Поскольку идентификаторы выше [1, 2].

Я хочу сделать это с Ramda.js.

Помогите мне.


Ладно, прости.

Я сделал что-то подобное.

let obj2 = {}
ids.forEach((x) => {
      obj2 += R.filter(y => y.id === x, obj)
      })
obj = obj2

Но это не правильно.

И я не хочу использоватьforEach.

Я хочу сделать с Ramda.js.

Ответы [ 5 ]

2 голосов
/ 08 марта 2019

Вы можете сделать это только с помощью Javascript, сначала вы можете создать набор с ids, который хотите сохранить (проверьте, имеет ли элемент элемент O(1)).Затем вы можете зациклить исходный object и добавить key с его value на новый object, если набор имеет id:

let obj = {
  tom: {id: 0},
  david: {id: 1},
  john: {id: 2}
}
let ids = [1, 2];

const filterByIds = (obj, ids) =>
{
    let idsSet = new Set(ids);
    let filteredObj = {};

    for (k in obj)
    {
        if (idsSet.has(obj[k].id))
            filteredObj[k] = obj[k];
    }
    
    return filteredObj;
}

console.log(filterByIds(obj, ids));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Обновление для использования Ramda:

С Ramda вы можете сделать так:

let obj = {
  tom: {id: 0},
  david: {id: 1},
  john: {id: 2}
}
let ids = [1, 2];
let idsSet = new Set(ids);

const hasValidId = o => idsSet.has(o.id);
let res = R.filter(hasValidId, obj);
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Легко, если вы прочитаете документацию здесь

1 голос
/ 08 марта 2019

Вообще говоря, вы должны стремиться работать со структурами данных, которые помогают вам, а не работают против вас.

С такой упрощенной структурой данных, как эта ниже:

const obj = [
  {id: 0, name: 'tom'},
  {id: 1, name: 'david'},
  {id: 2, name: 'john'}
]

Вы можете использовать innerJoin:

innerJoin((cur, id) => cur.id === id, obj, [1, 2])

Как преобразовать исходную структуру данных в упрощенную?

Это может быть двухэтапный процесс с Рамдой:

  1. Разделите ваш объект на массив пар ключ / значение с помощью toPairs:

    {tom:{id:0}} ~> [['tom', {id: 0}]]
    
  2. Отображение каждой пары в объект:

    [['tom', {id: 0}]] ~> [{name: 'tom', id: 0}]
    

const obj = {
  tom: {
    id: 0
  },
  david: {
    id: 1
  },
  john: {
    id: 2
  }
}

const convert = R.compose(R.map(([name, id]) => ({name, ...id})), R.toPairs);

console.log(convert(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
1 голос
/ 08 марта 2019

Вы можете сделать это в чистом JavaScript, используя Object.entries и деструктурируя с помощью includes следующим образом:

let obj = {
  tom: {
    id: 0
  },
  david: {
    id: 1
  },
  john: {
    id: 2
  }
};

let ids = [1, 2];

let result = {};

Object.entries(obj).forEach(([name, { id }]) => {
  if (ids.includes(id)) {
    result[name] = { id: id };
  }
});

console.log(result);
0 голосов
/ 08 марта 2019

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

Теперь я думаю, что это может помочь здесь. Вот что я бы сделал с Рамдой:

const matchIds = (obj, ids) => filter(propSatisfies(includes(__, ids), 'id'), obj)

let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}}
let ids = [1, 2]

console.log(matchIds(obj, ids))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {__, filter, propSatisfies, includes} = R
</script>

Альтернатива, особенно если список идентификаторов изменяется с меньшей вероятностью, чем объект, заключается в следующем:

const matchIds = (ids) => filter(propSatisfies(includes(__, ids), 'id'))

let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}}
let ids = [1, 2]

console.log(matchIds(ids)(obj))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {__, filter, propSatisfies, includes} = R
</script>

Есть несколько причин, чтобы не нравиться заполнитель ('__'). Если вы так думаете, вы можете заменить includes(__, ids) на flip(includes)(ids).

Обновление

Я не беру здесь свой совет. Хотя я бы все еще использовал Ramda для filter, здесь нет необходимости в propSatisfies. Простая лямбда отлично подойдет:

const matchIds = (ids) => filter(({id}) => ids.includes(id))

Это намного чище и удобочитаемее, по крайней мере, если вы привыкли к Рамда-норме частичного применения. (filter принимает два аргумента: функцию предиката и объект для фильтрации с ним. Поскольку мы предоставляем только первое, это возвращает нам функцию, ожидающую второго. Когда мы вызываем эту результирующую функцию с объектом, происходит фильтрация. )

Причина, по которой я все еще использовал бы Рамду filter, заключается в том, что не существует прямой встроенной версии этого применительно к объектам. Рамда предлагает простую альтернативу написанию одноразовой фильтрации объектов.

0 голосов
/ 08 марта 2019

Попробуйте:

let obj = { tom: { id: 0 }, david: { id: 1}, john: {id: 2} }
let ids = [1, 2] ;
let result = {} ;

for ( var o in obj ) {
  if (ids.includes(obj[o].id))
    result[o] = obj[o];
}

console.log(result) ;
...