部分镜头:按属性对对象数组进行分组,使用prop值作为键

时间:2018-11-15 12:58:19

标签: javascript lenses partial-lenses

我有一个这样的对象数组:

[
  { name: "Group 1", value: "Foo" },
  { name: "Group 2", value: "Bar" },
  { name: "Group 1", value: "Baz" }
]

我想使用Partial Lenses库将这些组转换为具有相应组项目的对象的键,如下所示:

{
  "Group 1": [
    { name: "Group 1", value: "Foo" },
    { name: "Group 1", value: "Baz" }
  ],
  "Group 2": [
    { name: "Group 2", value: "Bar" }
  ]
}

我当前的方法是这样的,假设我将源数据存储在名为data的变量中:

const grouped = L.collect([L.groupBy('name'), L.entries], data)
const setKey = [L.elems, 0]
const getName = [L.elems, 1, 0, 'name']
const correctPairs = L.disperse(setKey, L.collectTotal(getName, grouped), grouped)
L.get(L.inverse(L.keyed), correctPairs)

我不喜欢我需要使用groupedcorrectPairs变量来保存数据,因为我可能应该能够直接在合成中进行转换。您能帮我以更有意义的方式组合相同的功能吗?

这是上面代码的Partial Lenses Playground

3 个答案:

答案 0 :(得分:2)

我认为目标是实际创建同构,通过它可以 将这样的数组视为数组的对象,并执行更新。像一个 的双向版本拉姆达 R.groupBy功能。

实际上,一种方法是只使用Ramda的 R.groupBy实现新的原语 L.iso使用同构。 像这样:

const objectBy = keyL => L.iso(
  R.cond([[R.is(Array), R.groupBy(L.get(keyL))]]),
  R.cond([[R.is(Object), L.collect([L.values, L.elems])]])
)

需要条件,以允许数据不是 预期的类型,并在不存在的情况下将结果映射到undefined

这里是a playground with the above Ramda based objectBy 实施。

仅使用当前版本的偏光镜片,一种构成类似镜片的方法 objectBy组合器如下:

const objectBy = keyL => [
  L.groupBy(keyL),
  L.array(L.unzipWith1(L.iso(x => [L.get(keyL, x), x], L.get(1)))),
  L.inverse(L.keyed)
]

也许上面有趣的部分是转换 将数组数组转换为键数组对数组(或者相反)。 L.unzipWith1 检查组中的所有键是否匹配,如果不匹配,则检查该组 将被映射到undefined并被过滤掉 L.array。如果需要的话 可以通过使用更严格的行为 L.arrays

这里是a playground with the above composed objectBy 实施。

答案 1 :(得分:1)

您可以使用Array.reduce

let arr = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];

let obj = arr.reduce((a,c) => Object.assign(a, {[c.name]: (a[c.name] || []).concat(c)}), {});
console.log(obj);

答案 2 :(得分:1)

您不需要任何库,可以使用返回归约函数的泛型函数,从而可以使用任何键对任何集合进行分组。在下面的示例中,我用它来按名称分组,但也按值分组。

const groupBy = key => (result,current) => {
  let item = Object.assign({},current);
  // optional
  // delete item[key];
  if (typeof result[current[key]] == 'undefined'){
    result[current[key]] = [item];
  }else{
    result[current[key]].push(item);
  }
  return result;
};

const data = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];

const grouped = data.reduce(groupBy('name'),{});
console.log(grouped);
const groupedByValue = data.reduce(groupBy('value'),{});
console.log(groupedByValue);