How do you make that decision tasks?

The problem was in one of the interviews in it company.
Compress the list into ranges.
Given a list intov, duplicate items in the list.
Need to convert this set into a string by collapsing adjacent numeric row number in ranges.
Examples:
[1, 4, 5, 2, 3, 9, 8, 11, 0] => "0-5, 8-9, 11"
[1, 4, 3, 2] => "1-4"
[1, 4] => "1, 4"

Below is my solution, I want to understand how it is competent.
function range (arr) {
 arr.sort((a, b) => a - b)
 let str = arr[0]
 let iteration
 for (let i = 1; i < arr.length; i++) {
 if (arr[i] + 1 === arr[i + 1]) {
 iteration = true
 } else {
 if (!iteration) {
 str += ',' + arr[i]
 } else {
 str += '-' + arr[i]
 if (arr[i + 1] + 1 === arr[i + 2]) {
 str += ',' + arr[i + 1]
}
 iteration = false
}
}
}
 return str
}
April 3rd 20 at 17:18
8 answers
April 3rd 20 at 17:20
Solution
A bit crooked in my opinion, I would have done so

const range = arr => arr
 .sort((a, b) => a - b)
 .reduce((agg, v) => {
 const currRange = agg[agg.length - 1]
 if (!currRange || v > currRange.last + 1) {
 agg.push({first: "v" last: "v"})
 } else {
 currRange.last = v
}
 return agg
 }, [])
 .map(v => v.first + (v.first !== v.last ? '-' + v.last : ")).join()
April 3rd 20 at 17:22
Solution
What I hate:

  1. Mutating passed array
  2. For arrays of zero and unit length of the result string
  3. Too many IFS ever existed, it is too difficult

UPD. Oh and the results are crooked. View [ 1, 2 ], for example. Or [ 5, 6, 8, 9 ].
Ie, the problem is essentially not solved.
Thank you! - Wilfredo77 commented on April 3rd 20 at 17:25
And `;` no! Nuacho, no need to make life easier for the translator, he's smart, right? - Ryder_Crist commented on April 3rd 20 at 17:28
@Ryder_Crist, Yes, especially because ASI tightened, so as seldom to put these unnecessary squiggles. - Antonetta_Hermist commented on April 3rd 20 at 17:31
@Antonetta_Hermistthat the only people not going to be too lazy to justify. Because click 1 the button is selenaaa!!!!!

PS is Physiologically not take the code without ";" - Ryder_Crist commented on April 3rd 20 at 17:34
@Ryder_Crist, on the contrary, the code ";" looks cleaner.
However, all these squiggles and indentations - an improvement. You can tie automatic butifer, and to stop the suffering. - Antonetta_Hermist commented on April 3rd 20 at 17:37
@Antonetta_Hermist, cleaner or clearer?

However, Yes, the color of the markers. - Ryder_Crist commented on April 3rd 20 at 17:40
April 3rd 20 at 17:24
Solution
Your function can return a string can return a number, and may return undefined. This should not happen. Look below for test data. Then you manually build a string based on the array, it strongly reduces code readability, if you do not understand then do not understand what is happening there.

function range(array: number[]): string { 
 return array.sort(
 (a, b) => a - b
 ).reduce((acc, next, i) => {
 const prev = array[i - 1];

 if (prev !== undefined && next - prev === 1) {
 acc[acc.length - 1][1] = next;
}
 else {
acc.push([next]);
}

 return acc;
 }, []).map(
 arr => arr.join("-")
 ).join(", ");
}

console.log(range([1, 4, 5, 2, 3, 9, 8, 11, 0])); // 0-5, 8-9, 11
console.log(range([1, 4, 3, 2])); // 1-4
console.log(range([1, 4])); // 1, 4
console.log(range([1])); // 1
console.log(range([])); // ""
April 3rd 20 at 17:26
Solution
Offer your bike on crutches. No sorting!
const zip = arr => arr
 .reduce((agg, c) => {
 const iR = agg.indexOf(c + 1);
 const iL = agg.lastIndexOf(c - 1);
 if (!!~iR && !!~iL) agg.splice(iL, 2); // closed hole
 else if (!!~iR) agg[iR] = c; // moved the border
 else if (!!~iL) agg[iL] = c; // same
 else { // put the orphan to find a position immediately after less
 let pos = 0;
 while (pos < agg.length && agg[pos] < c) pos++;
 agg.splice(pos, 0, c, c); // inserted twice
}
 return agg;
 }, [])
 .reduce((agg, c, i, arr) => {
 if (!(i&1)) agg.push(arr[i+1] === c ? c : [c, arr[i+1]].join('-'));
 return agg;
 }, [])
 .join(', ')
;

An array of range, there is always an even number of elements.
Once the number is inserted into the array: searching, whether his next-door neighbors left and right.
  • If both are present, the number of closes "hole", you simply remove these two neighbors.
  • If there was only one model it by yourself, shifting the border.
  • If no neighbor, then the number is an orphan, insert it twice,
    like it and the left and right boundary of the range.
So from the first example is obtained [ 0, 5, 8, 9, 11, 11 ]
The formatting remains. Look only even elements. If the current and next elements are equal, it is the "alone" number. If not equal is the range with a hyphen. And bonded using a comma with a space.

Given sortirovanie collect the array, can be accelerated by replacing the indexOf() and lastIndexOf() to search in-house, stopping on the item, more or less desired.

Fiddle with tests

Beautiful workout for the mind. But if you weigh. On one side of the scales the asymptotic complexity (or simply complexity), and on the other a simple, fast, intuitive sort and one pass through the array. Obviously it is better to choose the latter. - Jacynthe commented on April 3rd 20 at 17:29
@Jacynthe, it is the warm-up. For that love Toaster QnA. - Jalen_Gra commented on April 3rd 20 at 17:32
April 3rd 20 at 17:28
Solution
You can use the fact that JavaScript reduce()is passed the current index and the array itself, it allows you to simplify backreference. In the end I got something like this:
/**
 * @param {Array} list
 * @return {string}
*/
const range = list => list
 .sort((a,b) => a - b)
 .reduce((r, v, i, a) => {
 if (i > 0 && v - a[i - 1] === 1) {
 let l = r.pop();
l.push(v);
r.push(l);
 } else {
r.push([v]);
}
 return r;
 }, [])
 .map(v => v.length > 1 ? `${v.shift()}-${v.pop()}` : v)
 .join(', ');

Piece with pop/push can be accelerated due to the complexity of the addressing arrays, but the code becomes more expressive.

Special thanks to @Camilla.Streich for .sort((a,b) => a - b) - did not know
So as not to sacrifice speed in favor of expressiveness just do the last function

const last = arr => arr[arr.length - 1];

const range = list => list
 .sort((a,b) => a - b)
 .reduce((r, v, i, a) => (i > 0 && v - a[i - 1] === 1 && last(r).push(v) || r.push([v])) && r [])
 .map(v => v.length > 1 ? `${v[0]}-${last(v)}` : v)
 .toString()
- Camilla.Streich commented on April 3rd 20 at 17:31
@Camilla.Streich, of course you Can, but the optimization problem did not seem staged, written in haste. - ewald commented on April 3rd 20 at 17:34
@ewald, Such things are stupid to even write in haste
let l = r.pop();
l.push(v);
r.push(l);


`${v.shift()}-${v.pop()}`

shift and pop change the array, as you might imagine. Just don't use them to refer to the first and the last element without needing to modify the array, then there will be nothing to optimize - Camilla.Streich commented on April 3rd 20 at 17:37
@Camilla.Streich, I Agree with you, although in the case of a conversion to a string mutation array is not the problem, it still ceases to exist at this stage. - ewald commented on April 3rd 20 at 17:40
@ewald, Waste of resources plus the curvature code - Camilla.Streich commented on April 3rd 20 at 17:43
April 3rd 20 at 17:30
Solution
The author, which they make?
My code solution universal works with repetitions. The classics
function range (a) {
 if (a.length < 2) return a
 a.sort( (a, b) => a-b )
 let pred = null
 let e = false
 let result = "
 for (let i of a) { 
 if (pred === null) { 
 result = pred = i
continue
}
 if (i != pred+1 ) {
 e ? result += '-' + pred + ', ' + i : result += ', ' + i
 e = false
 } else e = true
 pred = i
}
if (e) result += '-' + pred 
return result
}

console.log(range([1, 4, 5, 2, 3, 9, 8, 11, 0]))
console.log(range([1, 4, 3, 2]))
console.log(range([1, 4, 8]))

Or so
function range (a) {
 a.sort( (a, b) => a-b )
 a = [...a,"]
 return a.reduce((st, item, i, arr) => i==0 ? st += item : ( item != arr[i-1]+1 ) ? st += '-' + arr[i-1] + ', ' + item : st = st ")
.split(',')
 .map((item) => (eval(item) == 0 ? item.slice(0, item.indexOf('-')) : item).trim())
 .slice(0, -1)
 .join(', ')

}

console.log(range([1, 4, 5, 2, 3, 9, 8, 11, 0]))
console.log(range([1, 4, 3, 2]))
console.log(range([1, 4, 8]))

And full of idiomaticity will do so
const range = a => [...a.sort( (a, b) => a-b)"].reduce((st, item, i, arr) => i==0 ? st += item : ( item != arr[i-1]+1 ) ? st += '-' + arr[i-1] + ', ' + item : st = st ")
.split(',')
 .map((item) => (eval(item) == 0 ? item.slice(0, item.indexOf('-')) : item).trim())
 .slice(0, -1)
 .join(', ')

console.log(range([1, 4, 5, 2, 3, 9, 8, 11, 0]))
console.log(range([1, 4, 3, 2]))
console.log(range([1, 4, 8]))
Yandex gave. There's more, later I will upload.
You Yandex championship last were not involved? - Wilfredo77 commented on April 3rd 20 at 17:33
Participated, but gave up considering the amount of time. Here is a challenge similar to yours https://www.codewars.com/kata/51ba717bb08c1cd60f00002f. Searching realized that already did it a couple of years ago. For such problems, tests rule. My solution above (functional) is not complete will not be considered a negative number. Added:
const solution = a => [...a.sort( (a, b) => a-b)"].reduce((st, item, i, arr) => i==0 ? st += item : ( item != arr[i-1]+1 ) ? st += ' - ' + arr[i-1] + ', ' + item : st = st ")
.split(',')
 .map((item) => (eval(item) == 0 ? item.slice(0, item.indexOf(' - ')) : eval(item) == -1 ? item.replace(' - ',',') : item).trim())
 .slice(0, -1)
 .join(', ')
 .replace(/\s/g,")


This is a good Godwars. You can compare solutions. Here for a comparison of code written by someone's bright head, without sorting, in a functional style and with a minimum of code

function solution(nums){
 nums = nums.map((v, i) => nums[i - 1] == v - 1 && nums[i + 1] == v + 1 ? '-' : v);
 return nums.filter((v, i) => v != '-' || nums[i - 1] != '-').join(',').replace(/,-,/g, '-');
}
- Jacynthe commented on April 3rd 20 at 17:36
@Jacynthe, do you remember what your task A was?
Accidentally this is What you need to do in the problem? What do you mean protruding point?
For several days are unable to reach a complete solution - Wilfredo77 commented on April 3rd 20 at 17:39
April 3rd 20 at 17:32
At least the error that arr[i+1] and arr[i+2] will be undefined on the last iteration of the loop.
@reid_Nitzsche10, unless we get in the later iterations? - Wilfredo77 commented on April 3rd 20 at 17:35
@Wilfredo77, isn't it?

for (let i = 1; i < arr.length; i++)
- afton_Kassul commented on April 3rd 20 at 17:38
@afton_Kassul, in this condition, we still do not get, and will undefined1 undefined, you can of course, without a check to put that they generally defined

if (arr[i + 1] + 1 === arr[i + 2]) {
str += ',' + arr[i + 1]
}
- Wilfredo77 commented on April 3rd 20 at 17:41
@Wilfredo77, well, just do not fall, the MB then it is better to do the loop until arr.length - 2? To avoid any accessnow and undefined - afton_Kassul commented on April 3rd 20 at 17:44
@afton_Kassul, then it all will fall apart) - Wilfredo77 commented on April 3rd 20 at 17:47
@Wilfredo77, then the solution is not the best) way. You would also validation of arguments to make) - afton_Kassul commented on April 3rd 20 at 17:50
@afton_Kassulwhy skip two iterations? Here all iterations needed.

For validation of the arguments is a typescript.
Hold it at one funtion does not make sense, you need a factory, which will deal with the validation of arguments to functions. - deshawn.Ortiz5 commented on April 3rd 20 at 17:53
April 3rd 20 at 17:34
Oh namudrili colleagues. :) It's very simple, if you continute... :) If you don't sort, then less iterations does not work, so the same sort and not worried. :)

const rangeIt = data => {
 const a = [...data].sort((a, b) => a-b), r = [[a[0], a[0]]];
 for (i = 1; i < a.length; i++) {
 if (r[r.length - 1][1] + 1 === a[i]) {
 r[r.length - 1][1] = a[i];
 } else {
 r.push([a[i], a[i]]);
}
}
 return r.map(rr => rr[0] === rr[1] ? rr[0] : rr.join('-')).join(', ');
}


something like that :)

const rangeIt = data => {
 const a = [...data].sort((a, b) => a - b), r = [[a[0], a[0]]];
 const calcRanges = (n, i) => {
 if (!i) return;
 if (r[r.length - 1][1] + 1 === n) {
 r[r.length - 1][1] = n;
 } else {
 r.push([n, n]);
}
};
a.forEach(calcRanges);
 return r.map(rr => rr[0] === rr[1] ? rr[0] : rr.join('-')).join(', ');
}


or so

Find more questions by tags JavaScript