0

I am learning JS, and I have homework. I am asked to transform array into new array where each item is represented by the running count of element appearances.

For example

[1, 2, 1, 1, 3]

becomes

[1, 1, 2, 3, 1]

I wrote a code which works for numbers, but fails tests with strings:

UPDATE: IT works for some numbers, for others does not :/

function duplicates(arr) {

  let i, j, newArr = [],
    count = 1;

  for (i = 0; i < arr.length; i++) {
    for (j = 0; j < arr.length; j++) {
      if (i == j) {
        continue
      }
      if (arr[i] === arr[j]) {
        newArr.push(count++)
        break
      }
    }
    if (j === arr.length) {
      newArr.push(1)
    }
  }
  return newArr
}

console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2]  <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5]  <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ]  <-- MY CODE WORKS

Can you give me a hint? :/

Thank you!

Phil
  • 157,677
  • 23
  • 242
  • 245
Ma_Je
  • 23
  • 3
  • 4
    I just added a snippet to your question. Your code isn't producing the output you think it is. – Andy Feb 22 '22 at 23:31
  • 2
    Consider how you might build a map of the "frequencies" of each element. Eg, try to write code that transforms your array into an object like: `{"a": 3, "aa": 2}`, where the key is the array element and the value is the number of times it appears in the array. Then the rest is much easier, you just go through your array, and replace each element with the corresponding number from the map. – CRice Feb 22 '22 at 23:38
  • @Andy Thank you. I have changed my question. – Ma_Je Feb 22 '22 at 23:39
  • @Phil I have added another line of code, you can find a correct result there. – Ma_Je Feb 22 '22 at 23:40
  • The expected results don't seem to match up with your description. Why doesn't `[1,2,1,1,3]` become `[3,1,3,3,1]` since `1` occurs 3 times and `2` and `3` once each? – Phil Feb 22 '22 at 23:44
  • use reduce, expected should be [3,2], but also i agree with crise, to use key/value – Nonik Feb 22 '22 at 23:46
  • @Phil [1, 2, 1, 1, 3] - it becomes [ [1, 1, 2, 3, 1]. It depends when a duplicate is found. at which index (including the current index). First "1" does not have any duplicates yet. – Ma_Je Feb 22 '22 at 23:56
  • In that case, the description in your question could be better – Phil Feb 22 '22 at 23:57
  • @Phil yes, probably. Sorry for that. – Ma_Je Feb 23 '22 at 00:29
  • @Barmar hope you don't mind, I re-opened this as OP wants a running count, not totals – Phil Feb 23 '22 at 00:31
  • To maybe help you understand better CRice's suggestion: The "problem" with your current logic is that `count` doesn't know what it is counting, it just considers **any** duplicate values the same. What you want is to treat each values separately, i.e you need one `count` per unique value. – Kaiido Feb 23 '22 at 01:26

2 Answers2

0

One approach is to use .map(), .slice() and .filter()

const duplicates = (nums) =>
  nums.map((value, index) => {
    const segment = nums.slice(0,index+1);
    return segment.filter(v => v === value).length;
  });

console.log(duplicates([1, 2, 1, 1, 3]));
console.log(duplicates([1, 2, 1, 2, 3, 1]));
console.log(duplicates(['a', 'a', 'aa', 'a', 'aa']));
  1. map creates a new array by iterating through nums and transforming each value via a function
  2. slice is used to create a new array based on nums. In first example, the new array is [1] in first iteration, [1,2] in second, followed by [1,2,1] and so on.
  3. filter finds the items in the array from #2 that match the current value.
Ro Milton
  • 2,281
  • 14
  • 9
0

Elaborating on @CRice and @Kaiido idea, let's create an object that is creating the count of the items while you're looping through the array:

function duplicates(arr) {
  const obj = {};
  let value = 0;
  let newArr = [];
  for (i = 0; i < arr.length; i++) {
    value = arr[i];
    if (obj[value]){
       obj[value] = obj[value] + 1;
    }
    else{
       obj[value] = 1;
    }
    newArr.push(obj[value]);
  }
  return newArr
}


console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2]  <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5]  <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ]  <-- MY CODE WORKS

JS has a nice built-in, reduce, that does so in a simpler way:

const duplicates = (arr) => {
  const obj = {}
  return arr.reduce ( (acc,cur) => {
    obj[cur] = (obj[cur])?obj[cur]+1:1
    acc.push(obj[cur])
    return acc
  }, []);

}

console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2]  <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5]  <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ]  <-- MY CODE WORKS
malarres
  • 2,941
  • 1
  • 21
  • 35