Yami Odymel
Yami Odymel

Reputation: 1898

Grouping continuous number as "from~to" strings in JavaScript array

I have an array with numbers.

var myArray = [1, 2, 3, 5, 8, 9, 10];

and I'd like to group them into a string with a from~to format until the next value is not continuous with the previous value, like the following example.

var outputArray = ["1~3", "5", "8~10"];

How to do that?

Upvotes: 3

Views: 677

Answers (5)

user3255711
user3255711

Reputation: 1

For typescript, this function takes a sorted array of numbers and groups them into a single string.

function convertNumberArrayToRangeString(numbers: number[]): string {
    const delimiter = '~';
    return numbers
      .reduce((accumulator: string, currentValue: number, index: number, array: number[]) => {
        if (index > 0 && array[index - 1] + 1 !== currentValue) {
            if (index > 2 && array[index - 1] - array[index - 2] === 1) {
              accumulator +=  delimiter + array[index - 1].toString();
            }
            accumulator += ',' + currentValue.toString();
        } else if (index === 0 || index === array.length - 1) { // first or last
          if (array[index - 1] === currentValue - 1) {
            accumulator +=  delimiter;
          } else if (index > 0) {
            accumulator +=  ',';
          }
          accumulator += currentValue.toString();
        } 
        return accumulator;
      }, '');
  }

const list = [1, 2, 3, 6, 7, 8]; // sorted unique list
const groupedList = convertNumberArrayToRangeString(list);
console.log(groupedList);

Output> "1~3,6~8"

Upvotes: 0

Yami Odymel
Yami Odymel

Reputation: 1898

Click here for CodePen (or a Chinese(中文)version).

Basically just create a lastValue variable, and iterating the array. If the currentValue - 1 equals the lastValue then it's a continuous number. Create a new group once the condition failed.

In the final you just merge the groups with a string.

var newArray = [];
var tempArray = []; 
var oldArray = [1, 2, 3, 5, 8, 9, 10];
var lastValue = null;

oldArray.forEach(value => {
  if (lastValue != value - 1 || lastValue === null) {
    tempArray.push([value, value]);
  } else {
    tempArray[tempArray.length - 1][1] = value;
  }
  lastValue = value;
});

tempArray.forEach(value => {
  if (value[0] === value[1]) {
    newArray.push(value[0].toString());
  } else {
    newArray.push(value.join("~"));
  }
});

// OUTPUS: (3) ["1~3", "5", "8~10"]
document.write(JSON.stringify(newArray));

Upvotes: 0

symlink
symlink

Reputation: 12209

You can do this with Array.reduce() followed by Array.map():

const nums = [1, 2, 3, 5, 8, 9, 10]

const res = nums.reduce((acc, cur, idx, arr) => {
    if (idx === 0 || cur - 1 > arr[idx - 1]) {
        acc.push([cur])
    } else {
        acc[acc.length - 1].push(cur)
    }
    return acc
}, []).map(cur => cur.length > 1 ? cur.shift() + "~" + cur.pop() : cur[0])

console.log(res)

Upvotes: 2

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

Go thru only one time all elements. Whenever there is pattern of numbers not in sequence, just put them in results array.

var myArray = [1, 2, 3, 5, 8, 9, 10];

let start = myArray[0];
let end = myArray[0];
const results = [];

for (let i = 1; i < myArray.length; i++) {
  if (myArray[i] === (end + 1)) {
    end = myArray[i];
  } else {
    results.push((start === end) ? `${start}` : `${start}~${end}`);
    start = myArray[i];
    end = myArray[i];
  }
}
results.push((start === end) ? `${start}` : `${start}~${end}`);

console.log(results);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386654

You could take a slightly shorter approach by using the index to check if the first element needs an new array or if the value is not in order.

For the second mapping, you could just join all elements.

function group(numbers) {
    return numbers
        .reduce((result, value, index, array) => {
            if (!index || array[index - 1] + 1 !== value) {
                result.push([value]);
            } else {
                result[result.length - 1][1] = value;
            }
            return result;
        }, [])
        .map(array => array.join('~'));
}

console.log(group([1, 2, 3, 5, 8, 9, 10]));

Upvotes: 4

Related Questions