0

I am incrementing the value on rank by one till the name property changes, I am using the page and rank properties to determine when that happens.

But I would also like to increment it once when the type is not equal to none and resume when it does again.

I almost have it with this, but I seem to be one step behind, as when the type returns to none still not incrementing.

const data = [
  { name: 'car', rank: 1, page: 1, type: 'another' },
  { name: 'car', rank: 2, page: 1, type: 'none' },
  { name: 'car', rank: 1, page: 2, type: 'none' },
  { name: 'car', rank: 2, page: 2, type: 'none' },
  { name: 'bike', rank: 1, page: 1, type: 'none' },
  { name: 'bike', rank: 2, page: 1, type: 'none' },
  { name: 'bike', rank: 1, page: 2, type: 'something_else' },
  { name: 'bike', rank: 2, page: 2, type: 'something_else' },
  { name: 'bike', rank: 1, page: 3, type: 'something_else' },
  { name: 'bike', rank: 2, page: 3, type: 'none' }, 
  { name: 'moto', rank: 1, page: 1, type: 'not_none' },
  { name: 'moto', rank: 2, page: 1, type: 'not_none' },
  { name: 'moto', rank: 1, page: 2, type: 'none' },
  { name: 'moto', rank: 2, page: 2, type: 'none' },
  { name: 'bus', rank: 1, page: 1, type: 'none' },
  { name: 'bus', rank: 2, page: 1, type: 'none' },
  { name: 'bus', rank: 1, page: 2, type: 'none' },
]

let counter = 1

const results = data.reduce((acc, obj) => {

  if (obj.page === 1 && obj.rank === 1) 
    counter = 1

  obj.rank = obj.type === 'none' ? counter++ : counter

  acc.push(obj)
  return acc
}, [])

console.log(results)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Desired output

[
  { name: 'car', rank: 1, page: 1, type: 'other' },
  { name: 'car', rank: 2, page: 1, type: 'none' },
  { name: 'car', rank: 3, page: 2, type: 'none' },
  { name: 'car', rank: 4, page: 2, type: 'none' },

  { name: 'bike', rank: 1, page: 1, type: 'none' },
  { name: 'bike', rank: 2, page: 1, type: 'none' },
  { name: 'bike', rank: 3, page: 2, type: 'something_else' },
  { name: 'bike', rank: 3, page: 2, type: 'something_else' },
  { name: 'bike', rank: 3, page: 3, type: 'something_else' },
  { name: 'bike', rank: 4, page: 3, type: 'none' },

  { name: 'moto', rank: 1, page: 1, type: 'not_none' },
  { name: 'moto', rank: 1, page: 1, type: 'not_none' },
  { name: 'moto', rank: 2, page: 2, type: 'none' },
  { name: 'moto', rank: 3, page: 2, type: 'none' },

  { name: 'bus', rank: 1, page: 1, type: 'none' },
  { name: 'bus', rank: 2, page: 1, type: 'none' },
  { name: 'bus', rank: 3, page: 2, type: 'none' }
]

3 Answers 3

2

So the rank should increase when either the current or the previous type is "none". You can access the previous one via the third and fourth argument to reduce.

const data = [
  { name: 'car', rank: 1, page: 1, type: 'none' },
  { name: 'car', rank: 2, page: 1, type: 'none' },
  { name: 'car', rank: 1, page: 2, type: 'none' },
  { name: 'car', rank: 2, page: 2, type: 'none' },
  { name: 'bike', rank: 1, page: 1, type: 'none' },
  { name: 'bike', rank: 2, page: 1, type: 'none' },
  { name: 'bike', rank: 1, page: 2, type: 'something_else' },
  { name: 'bike', rank: 2, page: 2, type: 'something_else' },
  { name: 'bike', rank: 1, page: 3, type: 'something_else' },
  { name: 'bike', rank: 2, page: 3, type: 'none' }, 
  { name: 'moto', rank: 1, page: 1, type: 'not_none' },
  { name: 'moto', rank: 2, page: 1, type: 'not_none' },
  { name: 'moto', rank: 1, page: 2, type: 'none' },
  { name: 'moto', rank: 2, page: 2, type: 'none' },
  { name: 'bus', rank: 1, page: 1, type: 'none' },
  { name: 'bus', rank: 2, page: 1, type: 'none' },
  { name: 'bus', rank: 1, page: 2, type: 'none' },
]

let counter = 1

const results = data.reduce((acc, obj, i, data) => {

  if (obj.page === 1 && obj.rank === 1) 
    counter = 0;

  obj.rank = [obj.type, data[i-1]?.type].includes('none') || !i ? ++counter : counter;

  acc.push(obj)
  return acc
}, [])

console.log(results)
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

3 Comments

Nice, I forgot about the optional chaining ?.
There is one problem with this answer, if the first object type is also not none, its rank would be 0
True, I added || !i to deal with this.
1

const data = [
  { name: 'car', rank: 1, page: 1, type: 'none' },
  { name: 'car', rank: 2, page: 1, type: 'none' },
  { name: 'car', rank: 1, page: 2, type: 'none' },
  { name: 'car', rank: 2, page: 2, type: 'none' },
  { name: 'bike', rank: 1, page: 1, type: 'none' },
  { name: 'bike', rank: 2, page: 1, type: 'none' },
  { name: 'bike', rank: 1, page: 2, type: 'something_else' },
  { name: 'bike', rank: 2, page: 2, type: 'something_else' },
  { name: 'bike', rank: 1, page: 3, type: 'something_else' },
  { name: 'bike', rank: 2, page: 3, type: 'none' }, 
  { name: 'moto', rank: 1, page: 1, type: 'not_none' },
  { name: 'moto', rank: 2, page: 1, type: 'not_none' },
  { name: 'moto', rank: 1, page: 2, type: 'none' },
  { name: 'moto', rank: 2, page: 2, type: 'none' },
  { name: 'bus', rank: 1, page: 1, type: 'none' },
  { name: 'bus', rank: 2, page: 1, type: 'none' },
  { name: 'bus', rank: 1, page: 2, type: 'none' },
]

let counter = 1
let skip = false

const results = data.reduce((acc, obj) => {

  if (obj.page === 1 && obj.rank === 1) {
    counter = 0
    skip = false
  }
  if (obj.type !== 'none') {
    if (!skip) {
      skip = true
      counter++
    }
  } else {
    skip = false;
    counter++
  }
  
  obj.rank = counter

  acc.push(obj)
  return acc
}, [])

console.log(results)
.as-console-wrapper { max-height: 100% !important; top: 0; }

The condition could maybe be condensed to:

  if (obj.type === 'none' || !skip ) {
    skip = (obj.type !== 'none')
    counter++;
  }

3 Comments

Thanks for your answer, I actually managed to do it by using the index and array other arguments in the reduce method to go back in the array and check its type
Right. You need some kind of history information there. "Skip" was my choice.
I did this: if (obj.page === 1 && obj.rank === 1) counter = 0 if (obj.type === 'none' || index === 0) counter++ else if (index > 0 && array[index -1].type !== obj.type ) counter++
1

I ended up doing this, it addresses the fact that if the first object type is also not none it would still add rank 1, thanks to everyone for the responses and to trincot for remind me of the optional chaining

const data = [ { name: 'car', rank: 1, page: 1, type: 'other' }, { name: 'car', rank: 2, page: 1, type: 'none' }, { name: 'car', rank: 1, page: 2, type: 'none' }, { name: 'car', rank: 2, page: 2, type: 'none' }, { name: 'bike', rank: 1, page: 1, type: 'none' }, { name: 'bike', rank: 2, page: 1, type: 'none' }, { name: 'bike', rank: 1, page: 2, type: 'somethingelse' }, { name: 'bike', rank: 2, page: 2, type: 'somethingelse' }, { name: 'bike', rank: 1, page: 3, type: 'somethingelse' }, { name: 'bike', rank: 2, page: 3, type: 'none' }, { name: 'moto', rank: 1, page: 1, type: 'not_none' }, { name: 'moto', rank: 2, page: 1, type: 'not_none' }, { name: 'moto', rank: 1, page: 2, type: 'none' }, { name: 'moto', rank: 2, page: 2, type: 'none' }, { name: 'bus', rank: 1, page: 1, type: 'none' }, { name: 'bus', rank: 2, page: 1, type: 'none' }, { name: 'bus', rank: 1, page: 2, type: 'none' }, ]

let counter = 0

const relative = data.reduce((acc, obj, index, array) => {

  if (obj.page === 1 && obj.rank === 1) counter = 0
  if (obj.type === 'none' || array[index -1]?.type !== obj.type) counter++
  
  obj.rank = counter
  acc.push(obj)
  return acc
}, [])

console.log(relative)
.as-console-wrapper { max-height: 100% !important; top: 0; }

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.