如何根据 属性 对 javascript 数组进行分组?

How to group javascript array based on some property?

我有一个 JS 对象数组,如下所示:

var myArray = [
  { line: 20, text: [31, 80] },
  { line: 10, text: [80, 22] }
]

行在整个 myArray 中是唯一的,每行都有一些文本(不是唯一的)。 如何将每个文本与其对应的行匹配?

最后的结果应该是这样的:

var myNewArray = [
  { text: 31, line: [20] },
  { text: 80, line: [20, 10] },
  { text: 22, line: [10] }
]

可能最简单的方法是首先构建一个按文本索引行的中间 Map

const data = [
  {line: 20, text: [31,80]},
  {line: 10, text: [80,22]}
];

const result = [...data.reduce((map, {line, text}) => {
  text.forEach(t => {
    map.has(t) || map.set(t, []);
    map.get(t).push(line);
  });
  return map;
}, new Map()).entries()].map(([text, line]) => ({text, line}));

console.log(result);

一些方法 Map

因此您会得到一张临时地图,其中收集了所有 text,按 line 分组。要获取对象数组,请将 key/values 对映射为预定义的属性。

  • 因为有嵌套的数据数组,你需要对数据进行归一化以获得单个 line/text 值,然后按 [=13 添加分组=],

    const
        data = [{ line: 20, text: [31, 80] }, { line: 10, text: [80, 22] }],
        result = Array.from(
            data
                .flatMap(({ line, text }) => text.map(text => ({ text, line })))
                .reduce((m, { text, line }) => m.set(text, [...(m.get(text) || []), line]), new Map),
            ([text, line]) => ({ text, line })
        );
    
    console.log(result);
    

  • 或者一步完成,但使用减少外部数组(line)和内部数组(text 数组)的嵌套方法。

    const
        data = [
            { line: 20, text: [31, 80] },
            { line: 10, text: [80, 22] }
        ],
        result = Array.from(
            data.reduce(
                (m, { line, text }) => 
                    text.reduce(
                        (n, text) => n.set(text, [...(n.get(text) || []), line]),
                        m
                    ),
                new Map
            ),
            ([text, line]) => ({ text, line })
        );
    
    console.log(result);
    

这里有一个简单的解决方案。

var myArray = [
  { line: 20, text: [31, 80] },
  { line: 10, text: [80, 22] }
]

var myNewArray = []

myArray.forEach((item) => {
  item.text.forEach((t) => {
    const index = myNewArray.findIndex((e => e.text === t))
    index === -1
      ? myNewArray.push({text: t, line: [item.line]}) 
      : myNewArray[index].line.push(item.line)
  })
})

console.log(myNewArray)

方法如下:

var myArray = [
   { line: 20, text: [31, 80] },
   { line: 10, text: [80, 22] }
]

var newArray = myArray.reduce((acc, {line, text}) => {
  for( let t of text ){
    const match = acc.find(({text}) => text == t) // check if the text already exists in newArray 
    if( match ) match.lines.push(line) // if exists, add the line to that text
    else acc.push({text:t, lines:[line]}) // it not, create a new object with that line
  }
  return acc
}, [])

console.log( newArray )

或者首先生成一个对象而不是一个数组,如果你的数据集巨大更快 =31=],然后在最后将其转换为数组:

var myArray = [
   { line: 20, text: [31, 80] },
   { line: 10, text: [80, 22] }
]

// generate a key/value pairs for text/lines
var newArray = myArray.reduce((acc, {line, text}) => {
  for( let t of text )
    acc[t] = [...(acc[t] || []), line]
  return acc
}, {})

// convert the above Object to an Array of Objects (AKA Collection)
newArray = Object.entries(newArray).map(([text,lines]) => ({text, lines}))

console.log( newArray )