I have a JS array of objects like this:
var myArray = [
{ line: 20, text: [31, 80] },
{ line: 10, text: [80, 22] }
]
lines are unique in entire myArray , each line has some texts (which are not unique). How to match each text to its corresponding lines?
The final result should be like this:
var myNewArray = [
{ text: 31, line: [20] },
{ text: 80, line: [20, 10] },
{ text: 22, line: [10] }
]
CodePudding user response:
Some approaches with Map
.
As result you get a temporary map which collects all text
, grouped by line
. To get an array of objects, map the key/values pairs as eanted properties.
Because of having nested array of the data, you need eiter to normalize the data to get single
line
/text
values and then add a grouping bytext
,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);
Or do it in a single step but with a nested approach of reducing the outer (
line
) and inner arrays (text
arrays).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);
CodePudding user response:
Here's how:
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 )
Or by first generating an Object instead of an Array, which is faster if your dataset is huge, and then convert that to an Array at the end:
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 )
CodePudding user response:
Probably easiest by first building an intermediate Map
that indexes lines by text:
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);
CodePudding user response:
Here is a simple solution to your problem.
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)