使用Ramda.js过滤基于数组的对象

问题描述 投票:0回答:5
let obj = {
  tom: {
    id: 0
  },
  david: {
    id: 1
  },
  john: {
    id: 2
  }
}

let ids = [1, 2]

我想基于ids过滤obj。

我想要的结果是

{david:{id:1},约翰:{id:2}}

因为上面的ids是[1,2]。

我想用Ramda.js做这件事。

请帮我。


好吧,我很抱歉。

我做了这样的事。

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

但是,这是不正确的。

而且我不想使用forEach。

我想和Ramda.js一起做。

javascript arrays object ramda.js
5个回答
2
投票

你只能使用Javascript来做到这一点,首先你可以用你想要保留的ids创建一个集合(检查set是否有一个元素是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;}

Update to use 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>

如果你阅读文档here很容易


1
投票

您可以使用Object.entries在纯JavaScript中执行此操作,并使用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);

1
投票

一般来说,您应该努力使用帮助您而不是对您不利的数据结构。

使用简化的数据结构如下所示:

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

你可以使用innerJoin

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

如何将原始数据结构转换为简化数据结构?

与Ramda一起分为两个步骤:

  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>

0
投票

试试这个:

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) ;

0
投票

除非这是学习Ramda的练习,否则要注意想要在Ramda中这样做的想法。我是Ramda的主要作者之一,也是一个忠实粉丝,但我需要强调的是,它只是一个工具包而不是在某些情况下可以提供帮助。当它有所帮助时,很好,但它不应该是一个目标。

现在,我认为它可以在这里提供帮助。这就是我对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>

另一种选择,特别是如果id列表不太可能比对象更改,则:

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。一个简单的lambda将是完美的:

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

这个更清洁,更易读,至少一旦你习惯了部分应用的Ramda规范。 (filter有两个参数:谓词函数和用它过滤的对象。由于我们只提供第一个,这给了我们一个期望第二个的函数。当我们用对象调用那个结果函数时,就会发生过滤。)

我仍然使用Ramda的filter的原因是它没有应用于对象的直接内置版本。 Ramda提供了一种简单的替代方法来编写一次性对象过滤。

© www.soinside.com 2019 - 2024. All rights reserved.