12

I have following sorted array of numbers (they can repeat e.g 21)

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

And want to get following (sorted) array of strings with ranges

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

for consecutive numbers a,a+1,a+2,...,a+n=b w must create string "a-b" e.g for 6,7,8 we want to get "6-8", for "alone" numbers we want to get only that number e.g. for 12 in above example we get "12".

Here is my attempt but I stuck on it (and get headache)

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));

Update:

Here is "inversion" of this question

5 Answers 5

7

You could store the next expected value in a closure and reduce the array.

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]));

Sign up to request clarification or add additional context in comments.

3 Comments

This has an extra entry of '21' in the result that's not supposed to be there.
@KamilKiełczewski, in this case - is the wrong separator. for example with [-3, -2, -1] you would get [-3--1].
@NinaScholz yes, but I can easily change - to ... Thanks for update
3

This should do it for you.

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)

1 Comment

its must be string array
2

Another way could be

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)

1 Comment

Well spotted. Fixed the bug.
2

You don't need two loops, just keep track were you started the group:

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 Comments

I believe this does not yield the correct answer as it is. a) The last value is ignored, b) single value is not converted to string.
@sami fixed (not tested yet though)
I fixed the conversion too, now it seems to yield expected results.
@KamilKiełczewski I only changed previous -> "" + previous.
0

Here is also my answer (inspired by others answers)

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,'..')));

Explanation: g=[] contains result, first range element is f=a[0], at the begining we check does next element b=a[i+1] is equal or less than current element x plus one b<=x+1. If NO (which means that range ends or i is last index - b=undefined) then we push range to result g.push( f-x ? f+'-'+x : f+'' ) (we check here does x is not equal f by f-x -> f-x!=0 -> f!=x ), after push set first range element f to next range (element b).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.