Home > Net >  How does one, for an array of user items, merge the entries of consecutive user items where user nam
How does one, for an array of user items, merge the entries of consecutive user items where user nam

Time:01-21

Let say an array with inconsistent properties like the following :

[
    {user: 'user1', comment: 'This is a comment',},
    {user: 'user1', role: 'member'},
    {user: 'user1', role: 'writer'},
    {user: 'user2', role: 'admin'},
    {user: 'user1', comment: 'This is another comment'},
]

How to turn it so the objects will be grouped only if the next element in the array has the same property and belongs to the same user :

[
    {user: 'user1', comment: 'This is a comment'},
    {user: 'user1', role: [{'member', 'writer'}]},
    {user: 'user2', role: 'admin'},
    {user: 'user1', comment: 'This is another comment'},
]

CodePudding user response:

This solution too, is implemented as a reduce task.

The iterating task works with a lookbehind approach, comparing the current user item to the previous one. If both matching criteria (same user name and same property name) are met the process tries to look up an already existing merger object which would be referred to via the collector object. In case a previous merger did not happen a new merger object gets created from the previous user item and assigned to the collector. In any case the merger would be aggregated by the currently processed user item.

function mergeConsecutiveSameSoleUserEntry(collector, userItem, idx, arr) {
  let { merger, result } = collector;

  if (idx >= 1) {
    const { user: userName, ...soleEntry } = userItem;
    const { user: prevUserName, ...prevSoleEntry } = arr[idx - 1] ?? {};

    if (userName === prevUserName) {
      const [soleKey, soleValue] = Object.entries(soleEntry).at(0);
      const [prevSoleKey, prevSoleValue] = Object.entries(prevSoleEntry).at(0);

      if (soleKey === prevSoleKey) {
        if (!merger) {

          merger = collector.merger = {
            user: userName,
            [soleKey]: [prevSoleValue],
          };
          result[result.length - 1] = merger;
        }
        merger[soleKey].push(soleValue);

      } else {
        Reflect.deleteProperty(collector, 'merger');
        result.push(userItem);
      }
    } else {
      Reflect.deleteProperty(collector, 'merger');
      result.push(userItem);
    }
  } else {
    Reflect.deleteProperty(collector, 'merger');
    result.push(userItem);
  }
  return collector;
}

console.log([

  { user: 'user1', comment: 'This is a comment' },
  { user: 'user1', role: 'member' },
  { user: 'user1', role: 'writer' },
  { user: 'user1', role: 'observer' },
  { user: 'user2', comment: 'This is a comment' },
  { user: 'user2', role: 'writer' },
  { user: 'user2', role: 'admin' },
  { user: 'user1', role: 'admin' },
  { user: 'user1', role: 'observer' },
  { user: 'user1', comment: 'This is another comment' },

].reduce(mergeConsecutiveSameSoleUserEntry, { result: [] }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

You could try a recursive function like this

let data = [
  { user: 'user1', comment: 'This is a comment' },
  { user: 'user1', role: 'member' },
  { user: 'user1', role: 'writer' },
  { user: 'user2', role: 'admin' },
  { user: 'user1', comment: 'This is another comment' },
];
let combined = []

const combineRole = (curr, next, data) => {
  if (curr.user == next?.user) {
    curr.role = [curr.role, next.role].flat().filter(Boolean)
    return combineRole(curr, data.shift(), data)
  } else {
    return [curr, next]
  }
}

while (data.length) {
  // console.log(data)
  let [curr, next] = (combineRole(data.shift(), data.shift(), data))
  if (next)
    data.unshift(next)
  combined.push(curr)
}
console.log(combined)
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

You can use reduce to make something like that

const datas = [
  { user: 'user1', comment: 'This is a comment' },
  { user: 'user1', role: 'member' },
  { user: 'user1', role: 'writer' },
  { user: 'user1', role: 'observer' },
  { user: 'user2', comment: 'This is a comment' },
  { user: 'user2', role: 'writer' },
  { user: 'user2', role: 'admin' },
  { user: 'user1', role: 'admin' },
  { user: 'user1', role: 'observer' },
  { user: 'user1', comment: 'This is another comment' },
]

const datas2 = datas.reduce((s, d, x) => {
  if (x > 0) {
    const dk = Object.keys(d)
    if (dk.join(',') === Object.keys(s[s.length - 1]).join(',') && d.user === s[s.length - 1].user) {
      for (const k in dk) {
        if (dk[k] !== 'user' && d.hasOwnProperty(dk[k]) && s[s.length - 1].hasOwnProperty(dk[k])) {
          if (typeof s[s.length - 1][dk[k]] !== 'object')
            s[s.length - 1][dk[k]] = [s[s.length - 1][dk[k]]]
          s[s.length - 1][dk[k]].push(d[dk[k]])
        }
      }
      return s
    }
  }
  return s.concat(d)
}, [])

console.log(datas2);
.as-console-wrapper { min-height: 100%!important; top: 0; }

  •  Tags:  
  • Related