1

I'm trying to group my JavaScript array of objects by two attributes of the object contained between a range of 2 numbers, (in this case between start and start+2) this means every 2 seconds and then concat the content in an array.

var myArray = [
{
    start: 1.1,
    end: 1.6,
    content: "you"
},
{
    start: 1.8,
    end: 2.1,
    content: "should"
},
{
    start: 2.2,
    end: 2.5,
    content: "not"
},
{
    start: 2.9,
    end: 3.1,
    content: "be"
},
{
    start: 3.6,
    end: 4.0,
    content: "here"
},
{
    start: 4.5,
    end: 5.0,
    content: "please"
},
{
    start: 5.2,
    end: 5.8,
    content: "go"
},
{
    start: 5.9,
    end: 6.3,
    content: "away"
}
];

The idea is try to get this, note the max separation is between 2 secs.

var final = [
    {
        startArray: [1.1, 1.8, 2.2, 2.9],
        endArray: [1.6, 2.1, 2.5, 3.1],
        start: 1.1,
        end: 3.1,
        content: ["you", "should", "not", "be"]
    },
    {
        startArray: [3.6, 4.5],
        endArray: [4.0, 5.0],
        start: 3.6,
        end: 5.0,
        content: ["here","please"]
    },
    {
        startArray: [5.2, 5.9],
        endArray: [5.8, 6.3],
        start: 5.2,
        end: 6.3,
        content: ["go","away"]
    }
];    

How should I approach this problem? help :( !.

7
  • 9
    Have you made any attempt at all to solve this yourself yet? Please post the code you've tried Commented Aug 24, 2018 at 5:53
  • 1
    group objects in array based on value of key in object, Javascript Array grouping category Commented Aug 24, 2018 at 5:57
  • thanks @t.niese, I will try with the second one, I'm having trouble when I try to create the intervals. Commented Aug 24, 2018 at 5:59
  • When you say "the max separation is between 2 secs" between what two values are you referring? start of the first element in the group and end of the last? Commented Aug 24, 2018 at 6:04
  • Yes @Nick start and end are like time indicators Commented Aug 24, 2018 at 6:06

5 Answers 5

2

You can use Array.prototype.reduce iterate over the existing array and build your new array. Something like this:

let final = myArray.reduce((acc, item) => {
  let oldItem = acc.find(accItem => {
    // check if accItem is within two seconds of item
  });
  if (oldItem) {
    oldItem.startArray.push(item.start);
    // ... rest of the properties
  }
  else {
    return acc.concat({
      startArray: [item.start],
      endArray: [item.end],
      start: item.start,
      end: item.end,
      content: [item.content]
    });
  }
}, []);
Sign up to request clarification or add additional context in comments.

Comments

1

Using Array.reduce is the way to go:

var myArray = [
{
    start: 1.1,
    end: 1.6,
    content: "you"
},
{
    start: 1.8,
    end: 2.1,
    content: "should"
},
{
    start: 2.2,
    end: 2.5,
    content: "not"
},
{
    start: 2.9,
    end: 3.1,
    content: "be"
},
{
    start: 3.6,
    end: 4.0,
    content: "here"
},
{
    start: 4.5,
    end: 5.0,
    content: "please"
},
{
    start: 5.2,
    end: 5.8,
    content: "go"
},
{
    start: 5.9,
    end: 6.3,
    content: "away"
}
];
var final = [];
function groupValues(t, v, i, a) {
    print("item " + i);
    if (t.hasOwnProperty('start') && v.end <= t.start + 2) { 
        t.startArray.push(v.start); 
        t.endArray.push(v.end); 
        t.end = v.end; 
        t.content.push(v.content);
    }
    else {
        if (t.hasOwnProperty('start')) final.push(t);
        t = { startArray: [v.start],
             endArray: [v.end],
             start: v.start,
             end: v.end,
             content: [v.content]
            };
    }
    if (i == a.length - 1) final.push(t);
    return t;
}
myArray.reduce(groupValues, {});
console.log(final);

Output:

(3) […]   ​
0: {…}    ​​
content: Array(4) [ "you", "should", "not", "be" ]
end: 3.1    ​​
endArray: Array(4) [ 1.6, 2.1, 2.5, 3.1 ]    ​​
start: 1.1    ​​
startArray: Array(4) [ 1.1, 1.8, 2.2, 2.9 ]
​​
1: {…}    ​​
content: Array [ "here", "please" ]    ​​
end: 5    ​​
endArray: Array [ 4, 5 ]    ​​
start: 3.6    ​​
startArray: Array [ 3.6, 4.5 ]
​
2: {…}    ​​
content: Array [ "go", "away" ]    ​​
end: 6.3    ​​
endArray: Array [ 5.8, 6.3 ]    ​​
start: 5.2    ​​
startArray: Array [ 5.2, 5.9 ]

Comments

1

Base codes like below, no advanced things:

var final = [];
var j = 0;
for (var i = 0; i < myArray.length;) {
  var startArray = [];
  var endArray = [];
  var content = [];
  var start = myArray[j].start;
  var end = myArray[j].end;
  while ( i < myArray.length && (myArray[i].end - myArray[j].start) <= 2) {
    startArray[startArray.length] = myArray[i].start;
    endArray[endArray.length] = myArray[i].end;
    content[content.length] = myArray[i].content;
    end = myArray[i].end;

    i++;
  }
  final[final.length] = {
    startArray : startArray,
    endArray : endArray,
    start : start,
    end : end,
    content : content
  };

  j = i;
}
console.log(final);

Comments

0

If you sort the array first you only have to traverse the array and group neibhouring elements:

 function groupConsecutive(array, delay = 2) {
    array.sort((a, b) => a.start - b.start);

   let prev = { end: -Infinity }, current;
   const result = [];

   for(const {start, end, content } of array) {
     if(prev.end + delay >= start) {
       // Group
       current.content.push(content);
       current.startArray.push(start);
       current.endArray.push(end);
       current.start = Math.min(current.start, start);
       current.end = Math.max(current.end, end);
     } else {
       result.push(current = {
         startArray: [start],
         endArray: [end],
         content: [content],
         start,
         end,
      });
     }
   }

   return result;
 }

Comments

0

Assuming that the array is sorted, you can use Array.reduce

let myArray=[{start:1.1,end:1.6,content:"you"},{start:1.8,end:2.1,content:"should"},{start:2.2,end:2.5,content:"not"},{start:2.9,end:3.1,content:"be"},{start:3.6,end:4.0,content:"here"},{start:4.5,end:5.0,content:"please"},{start:5.2,end:5.8,content:"go"},{start:5.9,end:6.3,content:"away"}];
let obj;

let final = myArray.reduce((a, {start, end, content}, i) => {
  /* In case of first element and an exact difference of 2.0 for 
   * previous group, obj will be undefined, hence, initializing it. */
  if (!obj) {
    obj = {start, end, startArray: [start], endArray: [end], content: [content]};
  } else {
    let diff = end - obj.start; // calculate the difference
    // If the difference is less than or equal to 2, add object to group
    if (diff <= 2) {
      obj.startArray.push(start);
      obj.endArray.push(end);
      obj.content.push(content);
      obj.end = end;
      // If the difference is exact 2, add object to final array and reset
      if (diff == 2) {
        a.push(obj);
        obj = undefined;
      }
    } else {
      /* For difference more than 2, add current object to array 
       * and reset object will current value */
      a.push(obj);
      obj = {start, end, startArray: [start], endArray: [end], content: [content]};
    }
    /* At the end of iteration, if there is an object left, 
     * push it to final array */
    if(obj && i == myArray.length - 1) a.push(obj);
  }
  return a;
}, []);
console.log(final);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.