1

I have this array, that contains more arrays with objects inside that contains information about words founded in pages. Here one example:

let data = [
  [],
  [{
      "word": "society",
      "count": 5,
      "pageIndex": 1
    },
    {
      "word": "identity",
      "count": 2,
      "pageIndex": 1
    }
  ],
  [{
      "word": "society",
      "count": 2,
      "pageIndex": 2
    },
    {
      "word": "identity",
      "count": 2,
      "pageIndex": 2
    }
  ],
  [{
      "word": "society",
      "count": 2,
      "pageIndex": 3
    },
    {
      "word": "identity",
      "count": 1,
      "pageIndex": 3
    }
  ],
  [],
  [],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 6
  }],
  [],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 8
  }],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 9
  }]
]

What I want is to build a final array of objects with this structure to join the information of each word founded in just one object

const final = [{
    "word": "society",
    "countFinal": 12,
    "pagesIndexes": [1, 2, 3, 6, 8, 9]
  },
  {
    "word": "identity",
    "countFinal": 5,
    "pagesIndexes": [1, 2, 3]
  }
]

Any ideas on how to achieve this in JS?

3 Answers 3

3

You will first flat the data, afterward you can reduce (in order to group data based on word property). Once reduced, you can take Object.values of the object. Here is an implementation:

var data = [ [], [{ "word": "society", "count": 5, "pageIndex": 1 }, { "word": "identity", "count": 2, "pageIndex": 1 } ], [{ "word": "society", "count": 2, "pageIndex": 2 }, { "word": "identity", "count": 2, "pageIndex": 2 } ], [{ "word": "society", "count": 2, "pageIndex": 3 }, { "word": "identity", "count": 1, "pageIndex": 3 } ], [], [], [{ "word": "society", "count": 1, "pageIndex": 6 }], [], [{ "word": "society", "count": 1, "pageIndex": 8 }], [{ "word": "society", "count": 1, "pageIndex": 9 }]];

var result = Object.values(data.flat().reduce((a,{word, count, pageIndex})=>{
    a[word] = a[word] || {word, countFinal:0, pageIndexes:[]};
    a[word].countFinal+=count;
    a[word].pageIndexes.push(pageIndex);
    return a;
},{}));

console.log(result);

Sign up to request clarification or add additional context in comments.

3 Comments

wow, this is amazing. One question,is it possible to use flat already in node and in all browsers?
@Rusty23 yes, if you can include support of es2016 inside your angular project then it is possible.
@Rusty23 or if you have any third party library such as lodash or ramda then you have flatten or flat method to flat the array data.
1

var data = [
  [],
  [{
    "word": "society",
    "count": 5,
    "pageIndex": 1
  }, {
    "word": "identity",
    "count": 2,
    "pageIndex": 1
  }],
  [{
    "word": "society",
    "count": 2,
    "pageIndex": 2
  }, {
    "word": "identity",
    "count": 2,
    "pageIndex": 2
  }],
  [{
    "word": "society",
    "count": 2,
    "pageIndex": 3
  }, {
    "word": "identity",
    "count": 1,
    "pageIndex": 3
  }],
  [],
  [],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 6
  }],
  [],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 8
  }],
  [{
    "word": "society",
    "count": 1,
    "pageIndex": 9
  }]
];

let end_obj = {}
data.forEach(element => {
  element.forEach(sub => {
    if (!end_obj[sub.word]) {
      end_obj[sub.word] = {
        word: sub.word,
        countFinal: 0,
        pagesIndexes: []
      }
    }
    end_obj[sub.word].countFinal += sub.count
    end_obj[sub.word].pagesIndexes.push(sub.pageIndex)
  });
});

let end_arr = []
for (const key in end_obj) {
  const element = end_obj[key];
  end_arr.push(element)
}

console.log(end_arr);

Comments

1

One way could be to use a Map with .reduce(). The map would store keys which are the words from each object, along with its values being the modified objects with arrays for the pagesIndexes value. Whenever you come across a word that is already a key in the map, you can add to its pagesIndexes array. If you encounter a new word that isn't in the map, you can start a new array of its associated object which contains the current objects pageIndex. You can then grab the values from your Map using .values() and Array.from() to convert the value iterator into an array.

See example below

const data = [[], [{ "word": "society", "count": 5, "pageIndex": 1 }, { "word": "identity", "count": 2, "pageIndex": 1 } ], [{ "word": "society", "count": 2, "pageIndex": 2 }, { "word": "identity", "count": 2, "pageIndex": 2 } ], [{ "word": "society", "count": 2, "pageIndex": 3 }, { "word": "identity", "count": 1, "pageIndex": 3 } ], [], [], [{ "word": "society", "count": 1, "pageIndex": 6 }], [], [{ "word": "society", "count": 1, "pageIndex": 8}], [{ "word": "society", "count": 1, "pageIndex": 9 }] ];

const res = Array.from(data.reduce((acc, arr) => {
  return new Map([...acc, ...arr.map(c => {
    const o = acc.get(c.word);
    return [c.word, {...o, ...c, pagesIndexes: [...(o && o.pagesIndexes || []), c.pageIndex]}];
  })]);
}, new Map).values());

console.log(res);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.