【问题标题】:Split array with condition on element使用元素条件拆分数组
【发布时间】:2021-07-07 08:13:00
【问题描述】:

所以我有一个如下所示的数组:

[
  { date: '2021-07-07' },
  { date: '2021-07-07' },
  { date: '2021-07-07' },
  { date: '2021-07-08' },
  { date: '2021-07-09' },
  { date: '2021-07-10' },
  { date: '2021-07-10' }
];

如何拆分为 3 个数组(我的意思是 1 组用于唯一日期,另一组用于重复,但如果有超过 1 个重复组,则应分为另一组)

拆分后是这样的

Array 1
[{"date": "2021-07-07"},{"date": "2021-07-07"},{"date": "2021-07-07"}]
Array 2
[{"date": "2021-07-08"},{"date": "2021-07-09"}]
Array 3
[{"date": "2021-07-10"},{"date": "2021-07-10"}]

下面是我目前的代码,但它只有在副本上有 1 时才有效

const findDuplicates = arr => {
  let sorted_arr = arr.slice().sort();
  let result = [];
  for (let i = 0; i < sorted_arr.length - 1; i++) {
    if (sorted_arr[i + 1].date == sorted_arr[i].date) {
      result.push(sorted_arr[i]);
    }
  }
  return result;
};

const filterSame = arr => {
  let temp = findDuplicates(arr);
  const result = arr.filter(date => date.date == temp[0].date);
  return result;
};

const filterUnique = array => {
  let result = array.filter(
    (e, i) => array.findIndex(a => a['date'] === e['date']) === i
  );
  let temp = findDuplicates(array);
  result = result.filter(function(obj) {
    return obj.date !== temp[0].date;
  });
  return result;
};

【问题讨论】:

  • 为什么2021-07-082021-07-09 组合在一起?
  • @adiga 因为这不仅仅是一个简单的分组。这是一个分组,然后只用一个元素聚合所有内容。
  • 我将其理解为按日期对所有元素进行分组,其中有重复项,然后对所有唯一日期进行另一组。那主要基于预期结果TBH
  • @Jamiec 独特的去一个组,重复的去不同的组?
  • 这就是我理解问题的方式。它的描述不是特别好,但肯定比一个简单的组更重要

标签: javascript arrays filter


【解决方案1】:

您可以创建一个地图,以日期为键,并使用一个空数组作为值。然后填充这些数组。最后提取具有多个元素的数组,并将这些单元素数组的组合数组添加到该结果中:

function group(data) {
    let map = new Map(data.map(o => [o.date, []]));
    for (let o of data) map.get(o.date).push(o);
    return [
        ...[...map.values()].filter(({length}) => length > 1),
        [...map.values()].filter(({length}) => length == 1).flat()
    ];
}

let data = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}];

console.log(group(data));

说明

let map = new Map(data.map(o => [o.date, []]));

这会创建一个Map。构造函数被赋予一个对数组。对于数组看起来像这样的示例数据:

[
   ["2021-07-07", []],
   ["2021-07-07", []],
   ["2021-07-07", []],
   ["2021-07-08", []],
   ["2021-07-09", []],
   ["2021-07-10", []],
   ["2021-07-10", []]
]

Map 构造函数将创建相应的 Map,它真正删除了重复项。你可以想象它如下(虽然它不是一个普通的对象):

{
    "2021-07-07": [],
    "2021-07-08": [],
    "2021-07-09": [],
    "2021-07-10": []
}

然后for 循环将填充这(四个)数组,因此 Map 将如下所示:

{
    "2021-07-07": [{date:"2021-07-07"},{date:"2021-07-07"},{date:"2021-07-07"}],
    "2021-07-08": [{date:"2021-07-08"}],
    "2021-07-09": [{date:"2021-07-09"}],
    "2021-07-10": [{date:"2021-07-10"},{date:"2021-07-10"}]
}

return 语句中,Map 值被转换为数组两次。一次过滤具有超过 1 个元素的条目:

[
    [{date:"2021-07-07"},{date:"2021-07-07"},{date:"2021-07-07"}],
    [{date:"2021-07-10"},{date:"2021-07-10"}]
]

...第二次得到那些有 1 个元素的:

[
    [{date:"2021-07-08"}],
    [{date:"2021-07-09"}],
]

第二个数组被flat()扁平化:

[
    {date:"2021-07-08"},
    {date:"2021-07-09"},
]

最终结果使用展开语法 (...) 将第一个数组(具有重复日期)与扁平数组(具有唯一日期)连接起来

【讨论】:

  • 比起我自己的答案,我更喜欢这个答案。不错!
  • 它有效,如果你发表一些评论非常好,这样我就可以知道发生了什么,但无论如何谢谢你。
  • 为我的回答添加了解释。希望它能澄清它。
  • 此输入具有嵌套结构(对象数组数组),而您的问题具有对象数组。因此,在这种情况下,您必须先将 .flat() 应用于您的输入,然后再将其传递给我的答案中的函数。当然,重要的是您的输入具有一致的形状
  • 您是否实现了我在答案中对.flat() 的调用(我在发布初始答案后添加了一点)?
【解决方案2】:

这可以分两步完成

  1. 基于date 属性的典型操作分组
  2. 将只有 1 个结果的所有组聚合在一起。

const input = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}]

const grouped = input.reduce ( (acc,i) => {
    if(!acc[i.date]) acc[i.date] = []
    acc[i.date].push(i);
    return acc;
},{});

const final = Object.values(Object.entries(grouped).reduce( (acc,[key,values]) => {
   if(values.length>1) {
       acc[key] = values;
   }
   else{
      if(!acc.others) acc.others = [];
      acc.others.push(values[0]);
   }
   return acc
},{}))

console.log(final);

请注意,例如,如果您将 2021-07-11 添加到原始数组中,这将与所有其他“唯一”元素混为一谈。这可能是也可能不是您所期望的,但问题并不清楚。

【讨论】:

    【解决方案3】:

    另一个选项是在分组之前sort 数组。如果当前循环的date 与其邻居不同,则它没有重复。

    const input = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}]
    
    input.sort((a,b) => a.date.localeCompare(b.date))
    
    const grouped = input.reduce((acc, o, i, arr) => {
      const key = o.date === arr[i-1]?.date || o.date === arr[i+1]?.date
                    ? o.date
                    : 'lonely'
                    
      acc[key] ||= []
      acc[key].push(o);
      return acc;
    }, {});
    
    console.log(Object.values(grouped));

    【讨论】:

      猜你喜欢
      • 2018-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2018-10-10
      相关资源
      最近更新 更多