-1

I have array structured like this:

[
    [8,[1]],
    [15,[2]],
    [20,[3]],
    [23,[4,41]],
    [497,[18]],
    [1335,[38]],
    [2092,[39,55,61]],
    [3615,[5]],
    [4121,[14]],
    [5706,[39,55,61]],
    [5711,[62]],
    [5714,[63]],
    [5719,[64]],
    [6364,[38]]
]

I use the modified code from this answer to find consecutive numbers but I can't adapt it to also find consecutive numbers from arrays with multiple values

This is my code :

const a = [
    [8,[1]],
    [15,[2]],
    [20,[3]],
    [23,[4,41]],
    [497,[18]],
    [1335,[38]],
    [2092,[39,55,61]],
    [3615,[5]],
    [4121,[14]],
    [5706,[39,55,61]],
    [5711,[62]],
    [5714,[63]],
    [5719,[64]],
    [6364,[38]]
];

// this variable will contain arrays
let finalArray = [];
// Create a recursive function
function checkPrevNextNumRec(array) {
  let tempArr = [];
  // if the array contaon only 1 element then push it in finalArray and
  // return it
  if (array.length === 1) {
    finalArray.push(array);
    return
  }
  // otherside check the difference between current & previous number
  for (let i = 1; i < array.length; i++) {
    if (array[i][1][0] - array[i - 1][1][0] === 1) {
      // if current & previous number is 1,0 respectively 
      // then 0 will be pushed
      tempArr.push(array[i - 1]);
    } else {
      // if current & previous number is 5,2 respectively 
      // then 2 will be pushed
      tempArr.push(array[i - 1])
      // create a an array and recall the same function
      // example from [0, 1, 2, 5, 6, 9] after removing 0,1,2 it 
      // will create a new array [5,6,9]
      let newArr = array.splice(i);
      finalArray.push(tempArr);
      checkPrevNextNumRec(newArr)
    }
    // for last element if it is not consecutive of
    // previous number 
    if (i === array.length - 1) {
      tempArr.push(array[i]);
      finalArray.push(tempArr)
    }
  }
  }
checkPrevNextNumRec(a)

And here the result, as you can see, all the tables containing consecutive figures in [i][1][0] have been grouped

[
    [
        [8,[1]],
        [15,[2]],
        [20,[3]],
        [23,[4,41]]
    ],
    [
        [497,[18]]
    ],
    [
        [1335,[38]],
        [2092, [39,55,61]]
    ],
    [
        [3615,[5]]
    ],
    [
        [4121,[14]]
    ],
    [
        [5706,[39,55,61]]
    ],
    [
        [5711,[62]],
        [5714,[63]],
        [5719,[64]]
    ],
    [
        [6364,[38]]
    ]
]

But I need that field 5706 is also included with 5711, 5714, and 5719, but obviously it is not included because is not in [i][1][0] I thought of being inspired by this post but I cannot integrate it correctly

Can you help me?

Thanks!

  • I think that you want to compare the first element in `array[i][1]` with the last element in `array[i - 1][1]`. If that is correct, you can change `if (array[i][1][0] - array[i - 1][1][0] === 1) {...}` to `if (array[i][1][0] - array[i - 1][1][array[i - 1][1].length - 1] === 1) {...}` – Daniel W Strimpel Feb 21 '20 at 21:18
  • it's not exactly that, I want to compare all values in `array[i - 1][1][]` with all values in `array[i - 1][1][]`. I want 5706 to be grouped with 5711, 5714 and 5719 because these 4 have consecutive numbers in `array[i - 1][1][]`, and not because 61 is specifically in `array[i - 1][1][array[i][1].length - 1]` – Daniel Msika Feb 21 '20 at 21:38

3 Answers3

0

You need to check the last element of the grouped value.

const
    array = [[8, [1]], [15, [2]], [20, [3]], [23, [4, 41]], [497, [18]], [1335, [38]], [2092, [39, 55, 61]], [3615, [5]], [4121, [14]], [5706, [39, 55, 61]], [5711, [62]], [5714, [63]], [5719, [64]], [6364, [38]]],
    grouped = array.reduce((r, a) => {
        var last = r[r.length - 1];
        if (!last || last[last.length - 1][1][0] + 1 !== a[1][0]) r.push(last = []);
        last.push(a);
        return r;
    }, []);

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Basically the logic here is to iterate over the input and at each iteration, compare it with the data values from the previous iteration i.e.:prevData.

On each iteration, I used Array.prototype.map to create a new array that contains the what-would-be consecutive values (relative to the data in the previous iteration) by simply adding 1 to each item in prevData.

Next step is to loop that array to see if we encounter a consecutive value - as soon as we do we can break as there's no need to keep checking.

Finally is we apply the grouping logic with a single if/else.

const a = [
  [8, [1]],
  [15, [2]],
  [20, [3]],
  [23, [4, 41]],
  [497, [18]],
  [1335, [38]],
  [2092, [39, 55, 61]],
  [3615, [5]],
  [4121, [14]],
  [5706, [39, 55, 61]],
  [5711, [62]],
  [5714, [63]],
  [5719, [64]],
  [6364, [38]]
];

function group(input) {
  let prev;

  return input.reduce((accum, el) => {
    let hasConsecutive = false;
    const [key, current] = el;

    if (prev == null) {
      prev = current;
    }

    const consecutives = prev.map(n => n + 1);

    for (let i = 0; i < consecutives.length; i += 1) {
      if (current.includes(consecutives[i])) {
        hasConsecutive = true;
        break;
      }
    }

    if (prev && hasConsecutive) {
      accum[accum.length - 1].push(el);
    } else {
      accum.push([el]);
    }

    prev = current;

    return accum;
  }, []);
}

console.log(group(a));

Here's the result run through a beautifier:

[
    [
        [8, [1]],
        [15, [2]],
        [20, [3]],
        [23, [4, 41]]
    ],
    [
        [497, [18]]
    ],
    [
        [1335, [38]],
        [2092, [39, 55, 61]]
    ],
    [
        [3615, [5]]
    ],
    [
        [4121, [14]]
    ],
    [
        [5706, [39, 55, 61]],
        [5711, [62]],
        [5714, [63]],
        [5719, [64]]
    ],
    [
        [6364, [38]]
    ]
]
Tom O.
  • 5,730
  • 2
  • 21
  • 35
0

The following code enumerates each of the items in the array.

For each item, its sub-array is enumerated to see if the following item fits in a sequence.

If it fits in sequence, the next item is appended to a temporary variable, and we continue to the next item.

If the last entry in the subarray is reached without detecting a continuation of the sequence, we end the current sequence, start a new sequence and continue to the next item.

const data = [ [8,[1]], [15,[2]], [20,[3]], [23,[4,41]], [497,[18]], [1335,[38]], [2092,[39,55,61]], [3615,[5]], [4121,[14]], [5706,[39,55,61]], [5711,[62]], [5714,[63]], [5719,[64]], [6364,[38]] ]

function sequences(data) {
    const result = []        
    
    let sequence = [data[0]]
        
    for(let x=0; x<data.length-1; x++) {
      const [,sub] = data[x]
      
      for(let y=0; y<sub.length; y++) {
          const currSubV = sub[y]
          const [,nextSub] = data[x+1]
          if(nextSub.some((nextSubV) => currSubV+1 === nextSubV)) {
              sequence.push(data[x+1])
              break
          } 
          
          if(y === sub.length-1) {
              result.push(sequence)
              sequence = [data[x+1]]
          }
       }
    }
    return result
}

for(let s of sequences(data)) console.log(JSON.stringify(s).replace(/\s/g))
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • This solution seems almost perfect to me! it has only one small problem, if I add a 54 value to field 4121, the algorithm will include it with 5706, 5711, 5714 and 5719 (the numbers will not be consecutive, because the sequence will be `[14, 54][39, 55, 61][62][63][64]`, in my case, need the sequence to be `[14, 54][39, 55, 61]` and in a different field `[39, 55, 61][62][63][64]` Can you help me find a solution to this? Thanks – Daniel Msika Feb 23 '20 at 00:55
  • Do you have solution for me please? @Ben – Daniel Msika Feb 26 '20 at 01:07