sharif9876
sharif9876

Reputation: 680

JavaScript - iterate over object

I have an object like this that I get from an external endpoint so cannot change:

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}

I need to get it into a format like:

1: {
  1: { "time": 1, "day": 1 },
  2: { "time": 2, "day": 1 },
  3: { "time": 3, "day": 1 },
},
2: {
  1: { "time": 1, "day": 2 },
  2: { "time": 2, "day": 2 },
  3: { "time": 3, "day": 2 },
}

Where the first key is the day, and the second is the time.

My attempt doesn't work

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}

let test = {}

let defaultRow = {
  1: {},
  2: {}
}

Object.keys(obj).forEach((key) => {
  if (!test[obj[key]["day"]]) {test[obj[key]["day"]] = defaultRow}
  test[obj[key]["day"]][obj[key]["time"]] = obj[key]                                   
})

console.log(test)

Both days contain the same data for some reason. How can I achieve this? Any help is appreciated!

Upvotes: 1

Views: 156

Answers (10)

mplungjan
mplungjan

Reputation: 177685

My rather readable version

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}

let test = {}

for (let o in obj)  {
  const day  = obj[o].day;
  const time = obj[o].time;
  if (test[day]==undefined) { 
    test[day] = {}
  }
   test[day][time] = {day:day,time:time}
}

console.log(test)

Upvotes: -1

Ori Drori
Ori Drori

Reputation: 191916

Convert into an array of object using Object#values, and iterate the array using Array#reduce to convert to the desired format.

const obj = {"0":{"time":1,"day":1},"1":{"time":2,"day":1},"2":{"time":3,"day":1},"3":{"time":1,"day":2},"4":{"time":2,"day":2},"5":{"time":3,"day":2}};

const result = Object.values(obj).reduce((r, o) => {
  r[o.day] = Object.assign(r[o.day] || {}, { [o.time]: o }); 
  
  return r;
}, {});

console.log(result);

Upvotes: 0

Danmoreng
Danmoreng

Reputation: 2367

I don't really know why you need an object with properties 1...n instead of just using arrays for this purpose. I would solve it like this:

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
};

function orderByDay(obj){
    const result = {};
    Object.keys(obj).forEach(function(key){
        let day = obj[key].day;
        if(result.hasOwnProperty(day)){
            result[day].push(obj[key]);
        }else{
            result[day] = [obj[key]];
        }
    });
    return result;
}

console.log(orderByDay(obj));

Upvotes: 0

marvel308
marvel308

Reputation: 10458

// your code goes here
let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}

obj = Object.values(obj).reduce(function(newObject, val){
    //console.log(val.day, val.time, newObject);
    if(newObject[val['day']] == undefined)
        newObject[val['day']] ={};
    newObject[val['day']][val['time']] = val;
    //console.log(val.day, val.time, newObject);
    return newObject;
},{})

console.log(obj);
   /*
output
{ '1': 
   { '1': { time: 1, day: 1 },
     '2': { time: 2, day: 1 },
     '3': { time: 3, day: 1 } },
  '2': 
   { '1': { time: 1, day: 2 },
     '2': { time: 2, day: 2 },
     '3': { time: 3, day: 2 } } }
*/

Upvotes: 0

HollyPony
HollyPony

Reputation: 847

There is start with :

const result = Object.values(obj).reduce((accumulator, currentValue) => {
  if (!accumulator[currentValue.day]) accumulator[currentValue.day] = []
  accumulator[currentValue.day].push(currentValue)
  return accumulator
}, {})
console.log(result)

This is not THE solution but a starting kit :)

More infos: - MDN reduce - Stackoverflow search

Upvotes: 0

Selvakumar
Selvakumar

Reputation: 537

This will work for you

var result = Object.values(obj).reduce((count, currentValue) => {
    count[currentValue.day] = count[currentValue.day] || {};
    count[currentValue.day][Object.keys(count[currentValue.day]).length + 1] = currentValue;
    return count
}, {});

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386522

You could take the objects and build a new object with a new structure.

var object = { 0: { time: 1, day: 1 }, 1: { time: 2, day: 1 }, 2: { time: 3, day: 1 }, 3: { time: 1, day: 2 }, 4: { time: 2, day: 2 }, 5: { time: 3, day: 2 } },
    result = Object.values(object).reduce(
        (r, o) => ((r[o.day] = r[o.day] || {})[o.time] = o, r),
        {}
    );

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

Upvotes: 1

Anurag Singh Bisht
Anurag Singh Bisht

Reputation: 2753

To solve this problem, you need to iterate through your object and make value of day as your outer and increment the inner key as per the number of keys in the Object which you can get by Object.keys.length.

Here is the sample code.

let obj = {
  0: {
    "time": 1,
    "day": 1,
  },
  1: {
    "time": 2,
    "day": 1,
  },
  2: {
    "time": 3,
    "day": 1,
  },
  3: {
    "time": 1,
    "day": 2,
  },
  4: {
    "time": 2,
    "day": 2,
  },
  5: {
    "time": 3,
    "day": 2,
  }
}

let newObj = {};

for (let key in obj) {
  if(typeof newObj[obj[key]["day"]] !== "object") {
    newObj[obj[key]["day"]] = {};
  }
  let index = Object.keys(newObj[obj[key]["day"]]).length + 1;
  newObj[obj[key]["day"]][index] = obj[key];
}

console.log(newObj);

Upvotes: 0

charlietfl
charlietfl

Reputation: 171679

Both days contain the same data for some reason

Because you assign the same object reference defaultRow to each row. A simple fix is turn defaultRow into a function that returns a new object each time

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}

let test = {}

let defaultRow = function() {
  return {
    1: {},
    2: {}
  }
}

Object.keys(obj).forEach((key) => {
  if (!test[obj[key]["day"]]) {
    test[obj[key]["day"]] = defaultRow();
  }
  test[obj[key]["day"]][obj[key]["time"]] = obj[key]
})

console.log(test)

Simple example of the problem

var obj ={a:1},
    foo = obj,
    bar = obj;

foo.a=2;
console.log(bar.a) //returns  2 because is same object as foo

Upvotes: 2

Yury Tarabanko
Yury Tarabanko

Reputation: 45121

Since you want your nested objects to be plain objects not arrays the solution to get last index is rather involved.

let obj = {
  0: { "time": 1, "day": 1, },
  1: { "time": 2, "day": 1, },
  2: { "time": 3, "day": 1, },
  3: { "time": 1, "day": 2, },
  4: { "time": 2, "day": 2, },
  5: { "time": 3, "day": 2, }
}


console.log(
  Object.values(obj).reduce(
    (acc, value) => {
      const holder = acc[value.day] || (acc[value.day] = { })
      const keys = Object.keys(holder).map(key => +key)
      
      holder[keys.length ? (Math.max(...keys) + 1) : 1] = value
      return acc
    },
    {}
  )
)

Upvotes: 0

Related Questions