1

I was given this problem at one of my interviews and was told I have 20 minutes to solve it. This is the answer I came up with ( 2 versions ). Can you let me know which version you prefer and why, and if you have a better idea of how to solve it (less complex, less memory usage, etc.) Please share.

Problem: You have an array of random numbers that range from 0 to 100 elements.

  1. Write a function that will split this array into several arrays, each containing elements in the following range: (0-10],(10-20],(20-30], etc up to a 100].

  2. Write a function that outputs these arrays in a form of a simple graph, where each delimiter represents a single value in the array.

Array = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];


Desired outcome:

5  Elements in array: *****  -  1,5,6,3,4 
3  Elements in array: ***  -  10,12,11 
2  Elements in array: **  -  22,21 
No Elements in array. 
2  Elements in array: **  -  45,42 
3  Elements in array: ***  -  52,51,55 
2  Elements in array: **  -  64,65 
1  Elements in array: *  -  71 
No Elements in array. 
2  Elements in array: **  -  95,99 

// Version 1
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];

const splitArray = (inputArray, range) => {
  const newArray = [];
  do {
    let tempArray = [];
    tempArray = inputArray.filter((item) => {
      if (item >= range && item < range + 10) return item;
    });
    range += 10;
    newArray.push(tempArray);
  } while (range + 10 <= 100);
  return newArray;
};

const printArrays = (array, delimiter) => {
  let toPrint = "";
  for (index in array) {
    let stars = array[index].length;
    let string = "";
    for (let i = stars; i > 0; i--) {
      string += delimiter;
    }
    toPrint += stars
      ? `${stars}  Elements in array: ${string}  -  ${array[index]} \n`
      : "No Elements in array. \n";
  }
  return toPrint;
};

console.log(printArrays(splitArray(arr, 0), "*"));

// Version 2
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];

const getArrays = (inputArray) => {
  const newArray = [];
  let min = 0;
  let max = 10;
  do {
    const tempArray = [];
    for (i in arr) {
      let val = arr[i];
      val >= min && val < max ? tempArray.push(val) : "";
    }
    min += 10;
    max += 10;
    newArray.push(tempArray);
  } while (max <= 100);
  return newArray;
};

const printArrays = (array, delimiter) => {
  for (index in array) {
    let stars = array[index].length;
    let string = "";
    for (let i = stars; i > 0; i--) {
      string += delimiter;
    }
    console.log(
      stars ? `${stars}  Elements in array: ${string}  -  ${array[index]}` : "No Elements in array."
    );
  }
};

printArrays(getArrays(arr), "^");
LittleOldMe
  • 188
  • 1
  • 10
  • 3
    Hi. SO isn't a site to get opinions on working code you've written. – Andy May 28 '22 at 22:29
  • 1
    "Write a function that will split this array into several arrays, each containing elements in the following range: (0-10],(10-20],(20-30], etc up to a 100]." So, `10`, for example would appear in two arrays, right? – Lee Taylor May 28 '22 at 22:38
  • 1
    No, that notation in mathematics means the upper bound is exclusive. This is also the default for the vast majority of range-like operations in software, as it's the natural result of integer arithmetic. `9 / 10 == 0` vs `10 / 10 == 1`. – Eric Haynes May 28 '22 at 22:52
  • 1
    @LeeTaylor, no - Eric Haynes provided correct explanation so (0:10) = 10 > X > 0 (0:10] = 10>= X > 0 – LittleOldMe May 28 '22 at 22:57
  • @Andy Oh, can I ask why so? I am just trying to get better? This is not a production code, this is an interview question that I want to see if I could have solved better? – LittleOldMe May 28 '22 at 22:58
  • 1
    @DmitryDemin because (generally, and I say generally because CertainPerformance wrote a decent answer) SO isn't really a code forum. It's a question/answer site, and questions asking opinions _about_ code aren't really acceptable. You didn't do any harm but it would be worth taking another look at the site [help section](https://stackoverflow.com/help) when it comes to [asking a good question](https://stackoverflow.com/help/how-to-ask), and this [question checklist](https://meta.stackoverflow.com/questions/260648/stack-overflow-question-checklist). – Andy May 28 '22 at 23:03
  • 2
    This question is probably better suited to [codereview.se]. However be sure to take their [tour](https://codereview.stackexchange.com/tour) and read [A guide to Code Review for Stack Overflow users](https://codereview.meta.stackexchange.com/questions/5777/a-guide-to-code-review-for-stack-overflow-users) and their [How to Ask](https://codereview.stackexchange.com/help/how-to-ask) page before posting. – Nick May 28 '22 at 23:04
  • Ah, well thank you, Andy and Nick, noted! Getting back into coding world :) – LittleOldMe May 28 '22 at 23:08
  • 1
    Well, best of luck. Don't take our comments personally, it's like the Wild West here sometimes. :) @DmitryDemin Come back any time. – Andy May 28 '22 at 23:15

2 Answers2

3

Both approaches have moderate issues.


The first approach does

let tempArray = [];
tempArray = inputArray.filter((item) => {
  if (item >= range && item < range + 10) return item;
});

Better to just declare the tempArray as the filtered array to begin with.

const tempArray = inputArray.filter(...

Also, return item is suspicious inside a filter - all the filter callback cares about is whether its return value is truthy or falsey. Returning the array item when you actually want to indicate that the value should be included in the output is a common mistake. It happens not to be a problem here because 0 isn't a possibility, but it's still confusing. A better choice would be to do

const tempArray = inputArray.filter(
  item => item >= range && item < range + 10
);

(and maybe rename range to startOfRange)


Both of your approaches are also iterating through the entire input array multiple times (once for each range), which seems a bit wasteful - better to iterate through the input once.


Your second approach uses for (i in arr), and both approaches are doing for (index in array). This is a bad idea, and since you don't actually care about the index you're iterating over, it'd make sense to use for..of loops instead.


I think a better looking approach that iterates through the input just once would be:

const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];

const getArrays = (inputArray) => {
  const grouped = {};
  for (let i = 0; i < 100; i += 10) {
    grouped[i] = [];
  }
  for (const item of inputArray) {
    const rangeProp = Math.floor(item / 10) * 10;
    grouped[rangeProp].push(item);
  }
  return Object.values(grouped);
};

const printArrays = (groupedArrays, delimiter) => {
  for (const array of groupedArrays) {
    const stars = delimiter.repeat(array.length);
    console.log(
      stars
        ? `${array.length}  Elements in array: ${stars}  -  ${array.join(',')}`
        : "No Elements in array."
    );
  }
};

printArrays(getArrays(arr), "*");
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    I like your approach a lot more, I guess when I was writing the 1st function I was assuming an array output is expected, but that's clearly not the case. Nor I realize that we don't have to really specify the bracket itself, as long as we know the ballpark: what you have here: grouped[i] = []; Thank you! – LittleOldMe May 28 '22 at 23:06
0

I will do that this way :

This approach is simple: it retrieves the values one by one and adds them to the array corresponding to their range.

const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];


let ranges = arr.reduce((a,x)=>
  {
  let range = (x/10)|0  // get range start value 0 to 9
  a[range] ??= []       // create the array of if it does not already exist
  a[range].push(x) 
  return a
  },{})

console.log('ranges=', ranges ) // so that noobs can visualize this result

for (let r = 0; r < 10; r++ )
  {
  if (!ranges[r])
    document.write('No Elements in array.<br>')
  else
    {
    let count = ranges[r].length
    document.write(`${count} Elements in array: ${'*'.repeat(count)} - ${ranges[r].join(',')}<br>`)
    }
  }
.as-console-wrapper {max-height: 100% !important; width:20%; top: 0;
margin-left: 80%;  }
.as-console-row::after {display: none !important;}
 
range = (x/10)|0  // get range start value 0 to 9

example in case of x = 25 -> 25/10 give 2.5 and 2.5 | 0 give 2 -> integer part value of 2.5

| is the OR boolean operator, work only on integers values so it return an interger

??= is Logical nullish assignment

Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
  • _"I will do tha this way"_ is not a great answer if you're going to dump code without explaining what you've done to solve the problem - notes, links to MDN documentation etc. – Andy May 28 '22 at 23:08
  • This isn't about me being happy. It's about you providing the best possible answer. – Andy May 29 '22 at 00:12