使用对象分组数组项

Nun*_*ira 45 javascript

我的数组是这样的:

myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"}
]
Run Code Online (Sandbox Code Playgroud)

我想将其转换为:

myArray = [
  {group: "one", color: ["red", "green", "black"]}
  {group: "two", color: ["blue"]}
]
Run Code Online (Sandbox Code Playgroud)

所以,基本上,分组group.

我尝试着:

for (i in myArray){
  var group = myArray[i].group;
  //myArray.push(group, {???})
}
Run Code Online (Sandbox Code Playgroud)

我只是不知道如何处理类似组值的分组.

198*_*983 69

首先创建组名到值的映射.然后转换为您想要的格式.

var myArray = [
    {group: "one", color: "red"},
    {group: "two", color: "blue"},
    {group: "one", color: "green"},
    {group: "one", color: "black"}
];

var group_to_values = myArray.reduce(function (obj, item) {
    obj[item.group] = obj[item.group] || [];
    obj[item.group].push(item.color);
    return obj;
}, {});

var groups = Object.keys(group_to_values).map(function (key) {
    return {group: key, color: group_to_values[key]};
});

var pre = document.createElement("pre");
pre.innerHTML = "groups:\n\n" + JSON.stringify(groups, null, 4);
document.body.appendChild(pre);
Run Code Online (Sandbox Code Playgroud)

使用诸如reducemap之类的Array实例方法为您提供了强大的高级构造,可以为您节省手动循环的痛苦.


neu*_*aut 27

首先,在JavaScript中,使用迭代数组通常不是一个好主意for ... in.看看为什么在数组迭代中使用"for ... in"是一个坏主意?详情.

所以你可能会尝试这样的事情:

var groups = {};
for (var i = 0; i < myArray.length; i++) {
  var groupName = myArray[i].group;
  if (!groups[groupName]) {
    groups[groupName] = [];
  }
  groups[groupName].push(myArray[i].color);
}
myArray = [];
for (var groupName in groups) {
  myArray.push({group: groupName, color: groups[groupName]});
}
Run Code Online (Sandbox Code Playgroud)

groups这里使用中间对象有助于加快速度,因为它允许您避免嵌套循环来搜索数组.此外,因为groups是一个对象(而不是一个数组)迭代它使用for ... in是合适的.

附录

FWIW,如果要避免在结果数组中出现重复的颜色条目,可以if在行上方添加一个语句groups[groupName].push(myArray[i].color);以防止重复.使用jQuery看起来像这样;

if (!$.inArray(myArray[i].color, groups[groupName])) {
  groups[groupName].push(myArray[i].color);
}
Run Code Online (Sandbox Code Playgroud)

如果没有jQuery,你可能想要添加一个与jQuery相同的函数inArray:

Array.prototype.contains = function(value) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === value)
      return true;
  }
  return false;
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

if (!groups[groupName].contains(myArray[i].color)) {
  groups[groupName].push(myArray[i].color);
}
Run Code Online (Sandbox Code Playgroud)

请注意,在任何一种情况下,由于所有额外的迭代,您将减慢一些速度,所以如果您不需要避免结果数组中的重复颜色条目,我建议避免使用这些额外的代码.那里


hus*_*ayt 7

使用lodash的groupby方法

创建一个对象,该对象由通过iteratee运行集合的每个元素的结果生成的键组成.分组值的顺序由它们在集合中出现的顺序确定.每个键的对应值是负责生成密钥的元素数组.使用一个参数调用iteratee :( value).

因此,使用lodash,您可以在一行中获得所需的内容.见下文

let myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"},
]
let grouppedArray=_.groupBy(myArray,'group')
console.log(grouppedArray)
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

  • 结果不是所需的数据结构 (3认同)

und*_*ned 5

一种选择是:

var res = myArray.reduce(function(groups, currentValue) {
    if ( groups.indexOf(currentValue.group) === -1 ) {
      groups.push(currentValue.group);
    }
    return groups;
}, []).map(function(group) {
    return {
        group: group,
        color: myArray.filter(function(_el) {
          return _el.group === group;
        }).map(function(_el) { return _el.color; })
    }
});
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/dvgwodxq/

  • 非常优雅和自包含,很好.我唯一的抱怨是它不像一个简单的`for`循环那样立即可读. (3认同)

Nin*_*olz 5

除了使用两遍方法的给定方法之外,如果找到新组,您还可以通过推送该组来采取单循环方法。

var array = [{ group: "one", color: "red" }, { group: "two", color: "blue" }, { group: "one", color: "green" }, { group: "one", color: "black" }],
    groups = Object.create(null),
    grouped = [];

array.forEach(function (o) {
    if (!groups[o.group]) {
        groups[o.group] = [];
        grouped.push({ group: o.group, color: groups[o.group] });
    }
    groups[o.group].push(o.color);
});

console.log(grouped);
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run Code Online (Sandbox Code Playgroud)


Nic*_*ons 5

使用 ES6,这可以很好地使用.reduce()aMap作为累加器,然后使用Array.from()其映射函数将每个分组的映射条目映射到一个对象:

const arr = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}];

const res = Array.from(arr.reduce((m, {group, color}) => 
    m.set(group, [...(m.get(group) || []), color]), new Map
  ), ([group, color]) => ({group, color})
);

console.log(res);
Run Code Online (Sandbox Code Playgroud)

如果您的对象中除了groupand之外还有其他属性color,您可以采用更通用的方法,将分组对象设置为地图的值,如下所示:

const arr = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}];

const groupAndMerge = (arr, groupBy, mergeInto) => 
  Array.from(arr.reduce((m, o) => {
    const curr = m.get(o[groupBy]);
    return m.set(o[groupBy], {...o, [mergeInto]: [...(curr && curr[mergeInto] || []), o[mergeInto]]});
  }, new Map).values());

console.log(groupAndMerge(arr, 'group', 'color'));
Run Code Online (Sandbox Code Playgroud)

如果您可以支持可选链接空合并运算符 (??),则可以将上述方法简化为以下内容:

const arr = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}];
const groupAndMerge = (arr, groupBy, mergeWith) =>
  Array.from(arr.reduce((m, o) => m.set(o[groupBy], {...o, [mergeWith]: [...(m.get(o[groupBy])?.[mergeWith] ?? []), o[mergeWith]]}), new Map).values());

console.log(groupAndMerge(arr, 'group', 'color'));
Run Code Online (Sandbox Code Playgroud)