如何将JS数组转换成按天分组的形式

3
const arr = [
    {"datetime":"2018/8/5","value":85,"type":"A"},
    {"datetime":"2018/8/10","value":7,"type":"B"},
    {"datetime":"2018/8/10","value":73,"type":"A"}
];

我有一个数组,正如您在代码片段中所看到的。我的问题是我需要每天检查一些东西:

  1. 对于每天当 A value > 60 或者当 B value > 6 时做某事。
  2. 否则,当 A value <= 60B value <= 6 时做其他事情。

但我不知道如何使用当前数组结构进行此检查,因为循环中的每个步骤都是不同的一天。我想同时比较一天内的所有值。

是否可以将数组转换为以下格式?然后,我将能够逐日比较......

const arr = [
    {"datetime":"2018/8/5","valueA":85,"valueB":undefined},
    {"datetime":"2018/8/10","valueB":7,"valueA":73}
];

谢谢!

5个回答

1
你可以通过将日期分组并缩小为一个对象来实现。然后在该对象中设置适当的值。最终,你的数组将位于分组对象的Object.keys()中。
[正如你从评论中可能推测出的那样,最终数组的顺序不能保证,因为对象键和值不能保证。如果你的原始数据按日期排序,请在问题中说明,因为如果有保证顺序,将有更有效的方法来完成此操作]。

const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},{"datetime":"2018/8/10","value":7,"type":"B"},{"datetime":"2018/8/10","value":73,"type":"A"}];

let groups = arr.reduce((obj, {datetime, value, type}) => {
  if (!obj[datetime]) obj[datetime] = {datetime, valueA:undefined, valueB:undefined} 
  let currentKey = type == 'A' ? "valueA" : "valueB"
  obj[datetime][currentKey] = value
  return obj
},{})

let newArr = Object.values(groups)
console.log(newArr)


@Paulpro 在分组时无法保证顺序。一个日期可能在数组的开头,另一个日期可能在结尾。那个对象会放在最终数组中呢?如果 OP 说原始数组按日期排序,但这里并不知道,这可能是一个问题。您应该重新考虑这个踩的决定。 - Mark
如果输入的数组是有序的,那么可以保证。例如时间序列数据,就像这样。 - Paul
如果原始数组是有序的,我同意@Paulpro的观点,那么OP应该说出来。如果是这种情况,就会有其他解决方案,但由于OP从未说明数组是有序的,因此可能会被某些人投反对票。将最终结果排序非常简单。 - Mark
@Shidersz 我对所有的答案都进行了评论,因为我担心如果 OP 使用它们,他可能会认为它们适用于他的情况并愉快地使用它们(由于在尝试时,通常实际上会按照数组的顺序进行排序,即使这不是保证的),并且隐藏一个错误,这可能需要他或其他人花费大量时间和精力来调试。 - Paul
我认为答案至少应该提到即使输入是有序的,结果可能无序的潜在可能性,因为这很可能对OP很重要,而且他们也很可能不会注意到,因为它巧合地按照他们期望的顺序运行;但是它可能会在以后回来咬他们。如果日期符合ISO 8610,例如"2018-08-05",排序就会变得非常简单,只需使用newArr.sort(({datetime: a}, {datetime: b}) => (a < b) ? 1 : (a > b) ? -1 : 0);,但由于它们不符合ISO 8601,所以变得更加复杂。 - Paul
显示剩余2条评论

1
这将按照OP的要求转换数组,并保持顺序。

const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}];

var daysArr = []

arr.map(function(day){

    var keyName = 'value'+day.type
    var found = false
    var dayObj = {}

    for (var i=0; i < daysArr.length; i++) {
        if (daysArr[i].datetime === day.datetime) {
            daysArr[i][keyName] = day.value;
            found = true
            break
        }
    }

    if (!found) {
        dayObj = {"datetime":day.datetime,valueA:undefined,valueB:undefined}
        dayObj[keyName] = day.value
        daysArr.push(dayObj)
    }

})

console.log(daysArr);


这并不保证生成的数组会与输入的顺序相同。for ... in以任意顺序迭代对象键。 - Paul
修改了它。虽然不是最快的代码,也不是最现代化的,但这就是OP所要求的。顺序保留。 - ioannis

0

一个解决方案可以是使用reduce()。请注意,如果未定义key,将返回undefined(这在第二个日志中有例子),因此我认为定义例如"value-B": undefined是多余的,除非您想要将其分配给另一个默认值。

警告:如评论中所讨论的那样,您应该注意最终结果的顺序可能不会被保留。

const arr = [
  {"datetime":"2018/8/5","value":85,"type":"A"},
  {"datetime":"2018/8/10","value":7,"type":"B"},
  {"datetime":"2018/8/10","value":73,"type":"A"}
];

let res = arr.reduce((acc, {datetime, value, type: type}) =>
{
    acc[datetime] = acc[datetime] || {};
    Object.assign(acc[datetime], {datetime, [`value-${type}`]: value});
    return acc;
}, {});

console.log(Object.values(res));
console.log(Object.values(res)[0]["value-B"]);


这并不保证生成的数组与输入的顺序相同。在对象上调用Object.values会给出一个任意的顺序。 - Paul
@Paulpro,而且原帖明确表示他想保持顺序? - Shidersz
我从未说过他这样做。 - Paul
@Paulpro OP 需要比较每个日期的 A 和 B 值,因此我认为结果顺序并不重要。 - Slai
@Slai他还说他想为每个人做“某事”或“其他事情”。我认为这根本不清楚按顺序做这些事情是否重要。实际上,我认为相反的可能更正确。 - Paul

0

如果您不需要最终数组包含与原始日期时间相同的顺序,则可以创建一个将日期时间映射到相应值的对象,然后使用Object.values来获取最终数组。这种方法不能保证顺序,因为对象是无序数据结构:

const arr = [
  {"datetime":"2018/8/5","value":85,"type":"A"},
  {"datetime":"2018/8/10","value":7,"type":"B"},
  {"datetime":"2018/8/10","value":73,"type":"A"}
];

const values_by_date = { };
arr.forEach( ({ datetime, type, value }) =>
  values_by_date[ datetime ] = { 
    datetime/*, valueA: undefined, valueB: undefined*/,
    ...values_by_date[ datetime ], [`value${type}`]: value 
  }
);

const result = Object.values( values_by_date );
console.log( result );

如果您需要最终数组包含与原始数组相同顺序的日期时间,并且原始数组已按日期时间排序,则可以像这样一次性完成:

const arr = [
  {"datetime":"2018/8/5","value":85,"type":"A"},
  {"datetime":"2018/8/10","value":7,"type":"B"},
  {"datetime":"2018/8/10","value":73,"type":"A"}
];

const result = arr.reduce( ({ result, datetime: prev }, { datetime, type, value }) => {
  if ( datetime !== prev )
    result.push( { datetime/*, valueA: undefined, valueB: undefined*/ } );
  Object.assign( result[ result.length - 1 ], { [`value${type}`]: value } );
  return { result, datetime };
}, { result: [] } ).result;

console.log( result );

注意:在任何代码片段中,如果您希望生成的对象包括缺失值的属性,则可以取消注释/*,valueA: undefined, valueB: undefined*/

0
你可以这样做:
<html>
<head>
<meta charset="UTF-8"></meta>
<script type="text/javascript">
const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}];

var new_arr = group_items(arr)
console.log(new_arr)

function group_items(arr)
{
    var ret_arr = []
    for(var x=0;x<arr.length;x++)
    {
        var cur_date = arr[x].datetime
        var pos = lookup_date(cur_date, ret_arr)

        var obj = {}
        obj.datetime = cur_date
        if(pos != false)
        {
            //add to existing item

            if(arr[x].type == 'A')
            {
                ret_arr[pos].valueA = arr[x].value
            }
            else if(arr[x].type == 'B')
            {
                ret_arr[pos].valueB = arr[x].value
            }

        }
        else{
            if(arr[x].type == 'A')
            {
                obj.valueA = arr[x].value
            }
            else if(arr[x].type == 'B')
            {
                obj.valueB = arr[x].value
            }
            ret_arr.push(obj)
        }

    }

    return ret_arr
}

function lookup_date(date, arr)
{
    /*
        returns the position in arr of date
    */
    var retval = false
    for(var x=0;x<arr.length;x++)
    {
        if(arr[x].datetime == date)
        {
            retval = x
            break
        }
    }

    return retval
}
</script>
</head>
<body>
</body>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接