Louis
Louis

Reputation: 622

How to transform a js array to make it by day

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"}
];

I have an array as you can see in the snippet. My issue is I need to check something per day:

  1. For each day when A value > 60 or when B value > 6 then do something.
  2. Else when A value <= 60 and when B value <= 6 then do something else.

And I don't know how to do this check with the current array structure as each step in the loop is a different day. I want to compare all values for one day at the same time.

Is it possible to transform the array to look like this? Then I will be able to compare day per day...

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

Thank you!

Upvotes: 3

Views: 109

Answers (5)

Paul
Paul

Reputation: 141839

If you don't need the final array to include the datetimes in the same order as the original, then you can just make an object that maps datetimes to the corresponding values and then use Object.values to get the final array. This approach does not guarantee order, since objects are unordered data structures:

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 );

If you need the final array to include the datetimes in the same order as the original array and the original array is already sorted by datetime, you can do it in a single pass like this:

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 );

Note: In either snippet you can uncomment /*, valueA: undefined, valueB: undefined*/ if you want the resulting objects to include properties for the missing values.

Upvotes: 0

raphael75
raphael75

Reputation: 3238

You could do this:

<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>

Upvotes: 0

ioannis
ioannis

Reputation: 337

This will transform the array as OP asked for, and will respect the order.

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);

Upvotes: 1

Shidersz
Shidersz

Reputation: 17190

One solution could be using reduce(). Note that if a key is not defined will return undefined (this is exemplified on the second log to the console), so I consider redundant to define, for example "value-B": undefined, unless you want to assign to it another default value.

Warning: As discussed on the comments, you should note that the order of the final result, may not be preserved.

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"]);

Upvotes: 0

Mark
Mark

Reputation: 92440

You can make a the date groups by reducing into an object. Then just set the appropriate value in that object. In the end your array will be in the Object.keys() of the grouped object.

[As you might surmise from the comments, the order of the final array is not guaranteed because object keys and values are not guaranteed. If your original data is ordered by date, you should say so in the question because there will be more efficient ways to do this if the order is guaranteed].

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)

Upvotes: 1

Related Questions