3

I have a decently tricky javascript data manipulation problem that I am struggling with. I have the following array of data:

var myArray = [8, 13, 11, 17, 5, 13, 13];

And I would like to map this array into an array of equal length, where each value in the new array is equal to the difference between the array's previous value at that spot, and the next lowest value in the previous array. This is wordy, but for example, I want the output to be:

var newArray = [3, 2, 3, 4, 5, 0, 0]; 

3 in the first element is (8 - 5), where 8 is the array's previous value in the first slot, and 5 is the next lowest value in the previous array. 2 in the second element is (13 - 11), ... etc.

I'm not particularly caring how to handle ties (for example there are 2 values of 13 in the original array), so long as exactly one instance of 13 is replaced with (13 - next lowest value), and all other instances of 13 are replaced with zero (13 - 13 essentially).

Thanks!

9
  • 1
    Do you have any code base already? Commented Jun 4, 2018 at 19:56
  • I've spent time pondering the Q, but no I do not have code attempting a solution. This has the feeling of a Q where, once I have an approach on how to calculate it, the code is written in <1 minute. Commented Jun 4, 2018 at 19:58
  • 1
    What about negative values? Commented Jun 4, 2018 at 19:59
  • 1
    I'm actively working on it and will certainly post if i come up with a solution before an answer is posted Commented Jun 4, 2018 at 19:59
  • @VishnuKyatannawar there will never be negative values in my dataset Commented Jun 4, 2018 at 19:59

4 Answers 4

3

Using a reduce() within map() and checking if number is first instance or not using indexOf()

var arr = [8, 13, 11, 17, 5, 13, 13];

var res = arr.map((n, i) => {
  if (i !== arr.indexOf(n)) return 0;
  return n - arr.reduce((a, c) => c < n && c > a ? c : a, 0);
})

console.log(JSON.stringify(res))/// [3, 2, 3, 4, 5, 0, 0]

Alternate approach that creates descending sorted uniques array and then looks for number in next index within that array

var arr = [8, 13, 11, 17, 5, 13, 13];
var sortedUniques  = [...new Set(arr)].sort((a,b) => b-a);

var res = arr.map((n, i) => {
  if (i !== arr.indexOf(n)) return 0;
  var sortedIdx = sortedUniques.indexOf(n);
  return n - ( sortedUniques[sortedIdx+1] || 0 );
})

console.log(JSON.stringify(res))/// [3, 2, 3, 4, 5, 0, 0]

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

5 Comments

@VishnuKyatannawar why not? That seems like only an opinion. Was easy enough for me to read while writing it
Code is very intuitive. I may do a challenge in codegolf with this question and take this answer as an example
@charlietfl yup its just my opinion. Not used to writing code like this. This makes sense to me though.
@LuisfelipeDejesusMunoz think I have a more efficient idea. working on it
@LuisfelipeDejesusMunoz added what may be slightly more performant approach
1

Big thanks to @charlietfl who helped me to understand the part about the duplicates :) In general i came up with an almost identical solution, save for using Array.filter and Math.max instead of minimizing that to a single Array.reduce statement.

let myArray = [8, 13, 11, 17, 5, 13, 13],
    cmpArray = myArray.concat([0]);

console.log(
  myArray.map((value, index) => {
    if(index !== myArray.indexOf(value)) return 0;
    return value - Math.max(...cmpArray.filter(number => number < value));
  })
);

4 Comments

i see, i am having a hard time deciphering the requirements
if its a dup just return zero ... "all other instances of 13 are replaced with zero"
can i replace all 13 with 0, even if there would be 3 times 13 in it?
First one found is supposed to be evaluated. That's why I used indexOf() to check
1

You could collect the next values in an array and all array in an object and pop the values until all values are taken.

var array = [8, 13, 11, 17, 5, 13, 13],
    temp = array
        .slice()
        .sort((a, b) => b - a)
        .reduce(
            (r, v, i, a) => ((r[v] = r[v] || []).push(v - (a[i + 1] || 0)), r),
            Object.create(null)
        ),
    result = array.map(v => temp[v].pop());

console.log(result);

Comments

0

Something along these lines is getting close for me.

let newArray = [];
myArray.forEach(function(d){
  let temp = myArray.filter(val => val < d)
  let maxRemVal = d3.max(temp)
  maxRemVal = isNaN(maxRemVal) ? 0 : maxRemVal;
  newArray.push(d - maxRemVal)
});

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.