使用最大值和数量将多个对象减少为一个

时间:2018-10-16 14:49:37

标签: javascript arrays object

我有一个这样的对象数组:

    [
        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 3,
            collectTime: "15-OCT-2018 09:03:02",
            status: "unfinished"
        },

        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 2,
            collectTime: "14-OCT-2018 05:63:42",
            status: "unfinished"
        },

        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 5,
            collectTime: "15-OCT-2018 10:56:35",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 7,
            collectTime: "11-OCT-2018 13:12:41",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 10,
            collectTime: "15-OCT-2018 09:03:02",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 4,
            collectTime: "15-OCT-2018 22:36:32",
            status: "unfinished"
        },
    ]

但是,我似乎无法获得如下所示的数组:

    [
        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 5,  // highest occurrences value for the unique combination of name and mainName
            collectTime: "15-OCT-2018 10:56:35",  // collectTime corresponding to the highest occurrences
            finished: 1, // count of the status 
            unfinished: 2 // count of the status 
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 10, // highest occurrences value for the unique combination of name and mainName
            collectTime: "15-OCT-2018 09:03:02",  // collectTime corresponding to the highest occurrences
            finished: 2, // count of the status 
            unfinished: 1 // count of the status 
        },

    ]

我无法弄清楚您是如何使用Array.prototype.reduce()来获得所需的。我已经取得了一些进展,但无法完全获得确切的结果。任何指导都将不胜感激,谢谢!

5 个答案:

答案 0 :(得分:1)

很高兴向您展示您的努力,但是仍然可以为您提供一个可行的解决方案。希望这将为您的下一个项目提供有益的启发:

const arr = [
  {
    name: "aaa",
    mainName: "bbb",
    occurrences: 3,
    collectTime: "15-OCT-2018 09:03:02",
    status: "unfinished"
  },

  {
    name: "aaa",
    mainName: "bbb",
    occurrences: 2,
    collectTime: "14-OCT-2018 05:63:42",
    status: "unfinished"
  },

  {
    name: "aaa",
    mainName: "bbb",
    occurrences: 5,
    collectTime: "15-OCT-2018 10:56:35",
    status: "finished"
  },

  {
    name: "ccc",
    mainName: "ddd",
    occurrences: 7,
    collectTime: "11-OCT-2018 13:12:41",
    status: "finished"
  },

  {
    name: "ccc",
    mainName: "ddd",
    occurrences: 10,
    collectTime: "15-OCT-2018 09:03:02",
    status: "finished"
  },

  {
    name: "ccc",
    mainName: "ddd",
    occurrences: 4,
    collectTime: "15-OCT-2018 22:36:32",
    status: "unfinished"
  },
];

// Reduce the array
const res = arr.reduce((current, next) => {
  // Check whether the next item exists in the accumulator (current).
  const needle = current.find(i => i.name === next.name && i.mainName === next.mainName);
  // If it does...
  if (needle) {
    // increase the existing occurrences.
  	needle.occurrences += +next.occurrences;
    // increase the status counter according to the next status.
    needle[next.status] += 1;
    // replace the collectTime if needed.
    needle.collectTime = next.occurrences > needle.highestOccurrences ? next.collectTime : needle.collectTime;
    // Keep track of the highest occurrence found so far.
    needle.highestOccurrences = next.occurrences > needle.highestOccurrences ? next.occurrences : needle.highestOccurrences;
  }
  // Otherwise..
  else {
    // Create a "finished" property, and set it to 0.
  	next.finished = 0;
    // Create an "unfinished" property, and set it to 0.
    next.unfinished = 0;
    // Keep track of the highest occurrence for that item.
    next.highestOccurrences = next.occurrences;
    // Increase the status of that item accordingly.
    next[next.status] += 1;
    // Push this item to the accumulator.
  	current.push(next);
  }
  return current;
}, []).map(function(item){
  // Once done, just remove the undesired / unneeded properties.. BEWARE: this is unnecessary.
  delete item.highestOccurrences;
  delete item.status;
  return item;
});
console.log(res);

解释直接在代码中。

请注意,使用find代替过滤器,并使用单个reduce调用,已经可以很好地处理性能。

答案 1 :(得分:1)

如果找不到一个具有相同名称的对象,或者可以根据需要更新值,则可以采用一个新对象来缩小数组。

var data = [{ name: "aaa", mainName: "bbb", occurrences: 3, collectTime: "15-OCT-2018 09:03:02", status: "unfinished" }, { name: "aaa", mainName: "bbb", occurrences: 2, collectTime: "14-OCT-2018 05:63:42", status: "unfinished" }, { name: "aaa", mainName: "bbb", occurrences: 5, collectTime: "15-OCT-2018 10:56:35", status: "finished" }, { name: "ccc", mainName: "ddd", occurrences: 7, collectTime: "11-OCT-2018 13:12:41", status: "finished" }, { name: "ccc", mainName: "ddd", occurrences: 10, collectTime: "15-OCT-2018 09:03:02", status: "finished" }, { name: "ccc", mainName: "ddd", occurrences: 4, collectTime: "15-OCT-2018 22:36:32", status: "unfinished" }],
    result = data.reduce((r, { name, mainName, occurrences, collectTime, status }) => {
        var temp = r.find((o) => o.name === name);
        if (temp) {
            if (occurrences > temp.occurrences) {
                temp.occurrences = occurrences;
                temp.collectTime = collectTime;
            }
            temp[status]++;
        } else {
            r.push({
                name,
                mainName,
                occurrences,
                collectTime,
                finished: +(status === 'finished'),
                unfinished: +(status === 'unfinished') });
        }
        return r;
    }, []);

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

答案 2 :(得分:0)

filter将使您检查输出集中是否已经存在namemainName的组合。一旦确定了这一点,就可以在没有匹配该组合的情况下推入当前条目,或者根据出现次数是否更多来更新值。

var input =     [
        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 3,
            collectTime: "15-OCT-2018 09:03:02",
            status: "unfinished"
        },

        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 2,
            collectTime: "14-OCT-2018 05:63:42",
            status: "unfinished"
        },

        {
            name: "aaa",
            mainName: "bbb",
            occurrences: 5,
            collectTime: "15-OCT-2018 10:56:35",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 7,
            collectTime: "11-OCT-2018 13:12:41",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 10,
            collectTime: "15-OCT-2018 09:03:02",
            status: "finished"
        },

        {
            name: "ccc",
            mainName: "ddd",
            occurrences: 4,
            collectTime: "15-OCT-2018 22:36:32",
            status: "unfinished"
        },
    ]
    
  const output = input.reduce((arr, obj) => {
    let existing = arr.filter(t => t.name == obj.name && t.mainName == obj.mainName)[0]

    if(existing){
      if(obj.occurrences > existing.occurrences) {
        Object.assign(existing, obj)
      }
      if(existing[obj.status]) {
        existing[obj.status] += 1
      } else {
        existing[obj.status] = 1
      }
      delete existing.status
    } else {
      obj[obj.status] = 1
      delete obj.status
      arr.push(obj)
    }
    
    return arr
  }, [])
  
  console.log(output)

答案 3 :(得分:0)

这是-正如您提到的-经典.reduce问题,但是在这种情况下,您的备忘录将有两个实体。由于您需要跟踪许多不同的实体并进行汇总,因此建议将其保留为对象的对象(由于这样,访问对象会更快)。从计算的角度来看,使用对象对象比使用map中的另一个find或任何其他数组操作要便宜。

因此,您的memo用于reduce可能看起来像这样:

{
  'aaa': { 
     /* aaa content here */
  }, 
  'ccc': {
    /* ccc content here */
  }
}

然后,第二步,您可以标准化对象(将其转换为数组)。这样,您就不必每次都在reduce中迭代备忘录数组。

我将假设namemainName总是以相同的方式出现。如果存在多个组合,则必须调整“摘要”键才能使其唯一(例如memo[`${element.name}_${element.mainName}`]-为了清楚起见,我使用模板字符串);

1。遍历原始数组以减少“摘要”

const result = myArray.reduce((memo, element) => {
  const uniqueKey = `${element[name]}_${element.mainName}`;
  // Initialize new memo key, if not available yet
  if (!memo[uniqueKey]) {
    memo[uniqueKey] = {
       name: element.name,
       mainName: element.mainName,
       collectTime: element.collectTime,
       occurrences: element.occurences,
       finished: element.status === 'finished' ? 1 : 0,
       unfinished: element.status === 'unfinished' ? 1 : 0,
    };
  }

  // I assume there are only 2 statuses here available
  if (element.status === 'finished') {
    memo[uniqueKey].finished = memo.finished + 1;
  } else {
    memo[uniqueKey].unfinished = memo.unfinished + 1;
  }

  // Increase occurences, if needed
  if (memo[uniqueKey].occurences < element.occurences) {
    memo[uniqueKey].occurences = element.occurences;
    memo[uniqueKey].collectTime = element.collectTime;
  }
}, {});

2。将备忘录转换为数组。请注意,备忘录很短,因此转换很便宜:

const newArray = Object.values(result);

答案 4 :(得分:0)

使用Object键作为键,还原为name,使用Object.values检索Array的结果值(对象)。 注意:摘录getValues中的代码仅以实际的reducer代码开头。

const grouped = Object.values(
  getValues().reduce( (collection, value) => {
    const isFinished = value.status === "finished";
    const current = collection[value.name];
     if (!current) {
       collection[value.name] = { ...value,
        finished: +(isFinished), 
        unfinished: +(!isFinished) };
       delete collection[value.name].status;
     } else {
       collection[value.name] = { ...current,
        occurrences: Math.max(value.occurrences, current.occurrences),
        collectTime: new Date(current.collectTime) < new Date(value.collectTime) 
          ? value.collectTime 
          : current.collectTime ,
        finished:  +(isFinished) + current.finished,
        unfinished: +(!isFinished) + current.unfinished  };
     }
     return collection;
  }, {} )
);

console.log(grouped);

function getValues() {
  return [
    {
        name: "aaa",
        mainName: "bbb",
        occurrences: 3,
        collectTime: "15-OCT-2018 09:03:02",
        status: "unfinished"
    },

    {
        name: "aaa",
        mainName: "bbb",
        occurrences: 2,
        collectTime: "14-OCT-2018 05:63:42",
        status: "unfinished"
    },

    {
        name: "aaa",
        mainName: "bbb",
        occurrences: 5,
        collectTime: "15-OCT-2018 10:56:35",
        status: "finished"
    },

    {
        name: "ccc",
        mainName: "ddd",
        occurrences: 7,
        collectTime: "11-OCT-2018 13:12:41",
        status: "finished"
    },

    {
        name: "ccc",
        mainName: "ddd",
        occurrences: 10,
        collectTime: "15-OCT-2018 09:03:02",
        status: "finished"
    },

    {
        name: "ccc",
        mainName: "ddd",
        occurrences: 4,
        collectTime: "15-OCT-2018 22:36:32",
        status: "unfinished"
    },
  ];
}