Создать строковые диапазоны из отсортированного массива целых чисел

У меня есть следующий отсортированный массив чисел (они могут повторяться, например, 21)

let a = [1,2,3,4,7,8,12,15,21,21,22,23]

И хочу получить следующий (отсортированный) массив строк с диапазонами

let r =["1-4","7-8","12","15","21-23"]

для последовательных чисел a, a + 1, a + 2,..., a + n = bw необходимо создать строку "ab", например, для 6,7,8 мы хотим получить "6-8", для "одних" чисел мы хотим получить только это число, например, для 12 в приведенном выше примере мы получаем "12".

Вот моя попытка, но я застрял на ней (и у меня болит голова)

let a = [1,2,3,6,7,8,12,15,21,21,22,23];
let right=a[0];
let left=a[0];
let result=[];

for(let i=1; i<a.length; i++) {
	for(let j=1; j<a.length; j++) {
      if(a[i]<a[j])result.push('${a[i]}-${a[j]}');
      
  }
}

console.log(JSON.stringify(result));

Ответы

Ответ 1

Вы можете сохранить следующее ожидаемое значение в замыкании и уменьшить массив.

function getRanges(array) {
    return array.reduce((l => (r, v, i, a) => {
        if (l[1] > v) return r;
        r.push(l[1] === v
            ? (r.pop(), l.join('-'))
            : (l = [v, v]).slice(0, 1).toString()
        );
        l[1]++;
        return r;
    })([]), []);
}

console.log(getRanges([-3, -2, -1, 2]));
console.log(getRanges([1, 2, 3, 4, 7, 8, 12, 15, 21, 21, 22, 23]));

Ответ 2

Это должно сделать это для вас.

const a = [1,2,3,4,7,8,12,15,21,21,22,23,27]

let min = a[0], last = a[0]

const result = a.reduce((arr, n, i) => {
  if(n - last > 1){
    if(min == last) arr.push(""+min)
    else arr.push([min, last].join("-"))
    
    min = n
  }
  
  if(i == a.length - 1) {
    if(min == n) arr.push(""+min)
    else arr.push([min, n].join("-"))
  }
  
  last = n
  
  return arr
}, [])

console.log(result)

Ответ 3

Вам не нужно две циклы, просто следите, где вы начали группу:

let array = [1,2,3,4,7,8,12,15,21,21,22,23]

const groups = [];
let start = array[0];

array.push(NaN);

for(let index = 1; index < array.length; index++) {
  const value = array[index], previous = array[index - 1];
  if(value === previous + 1 || value === previous) 
     continue;

  if(start === previous) {
    groups.push("" + previous);
  } else {
    groups.push(start + "-" + previous);
  }
  start = value;
}

console.log(groups);

Ответ 4

Другой способ может быть

let a = [1,2,3,4,7,8,12,15,21,21,22,23]

let r = a.reduce((acc, val) => {
  const lastGroup = acc.pop() || [];
  const lastValue = lastGroup.slice(-1)[0];
  if (val - lastValue > 1) {
    return [...acc, lastGroup, [val]];    
  }
  return [...acc, [...lastGroup, val]];
}, []).map(group => {
  const first = group[0];
  const last = group[group.length-1];
  return first !== last ? '${first}-${last}' : '${first}';
});

console.log(r)

Ответ 5

Еще один короткий путь:

a.reduce((acc, ele, i) => {
    if(acc.length === 0) return acc.concat(ele);
    if(ele === a[i - 1] + 1 || ele === a[i - 1]) return acc; 
    acc[acc.length-1] = '${acc[acc.length-1]}-${ele}'
    return acc.concat(ele.toString());
}, []);

Ответ 6

Вот и мой ответ (вдохновленный ответами других)

let r = (a,c='-',f=a[0],g=[]) => (a.map((x,i,a,b=a[i+1]) =>
        b<=x+1 ? 0 : (g.push( f-x ? f+c+x : f+'' ),f=b) ),g);

let a = [1,2,3,4,7,8,12,15,21,21,22,23];
let b = [-7,-5,-4,-3,-1,0,1,3,4,5,8]; 

let r = (a,c='-',f=a[0],g=[]) => (a.map((x,i,a,b=a[i+1]) =>
        b<=x+1 ? 0 : (g.push( f-x ? f+c+x : f+'' ),f=b) ),g);

let J= JSON.stringify;
console.log(J(a) + ' -> ' + J(r(a)));
console.log(J(b) + ' -> ' + J(r(b,'..')));

Ответ 7

Это должно дать желаемый результат.

let a = [1,2,3,4,7,8,12,15,21,21,22,23];

let r = [];
let start = a[0];
let end = 0;

for (let i = 1; i <= a.length; i++) {
  if (a[i] == r[r.length - 1]) {
    r.pop();
  }

  if (!a[i] || a[i] !== a[i-1] + 1) {
    end = a[i - 1];
    if (start === end) {
      r.push(start.toString());
    } else {
      r.push(start + '-' + end);
    }
    if (a[i]) {
      start = a[i];
    }    
  }
}


console.log(r);