-8
var rank1 = 0
var rank2 = 0
var rank3 = 0
var rank4 = 0

const array1 = [Rank1, Rank1, Rank1, Rank3]

var Rank1 = Rank1
var Rank2 = Rank2
var Rank3 = Rank3
var Rank4 = Rank4

array1.forEach((Rank1) => {
  rank1++
});
array1.forEach((Rank2) => {
  rank2++
});
array1.forEach((Rank3) => {
  rank3++
});
array1.forEach((Rank4) => {
  rank4++
});

I'm trying to loop through array1 and save the number of times each item occurred in the array to their var.

For example, if array contains two Rank1, I want the variable rank1 to be equal to 2.

if i console.log rank1, rank2, rank3, rank4 i get the result 4,4,4,4 instead of the wanted result that would be 3,0,1,0 in this case

  • I did my best to reformat your question. The code was formatted as a string literal with escape sequences and everything. I must admit, that's the first time I've seen that happen. There are still specific problems with case of variables and such. And your question is not very clear. But it sounds like you want to count the number of occurrences of each unique value in an array, like a histogram. Is that right? – Wyck Mar 26 '22 at 19:08
  • please add your data and the wanted result. – Nina Scholz Mar 26 '22 at 19:08
  • @Wyck thank you for your edit ! yes i am trying to count the number of occurrence of each var in the array – theo karam Mar 26 '22 at 19:15
  • 2
    @Wyck The formatting is caused by [this bug](//meta.stackoverflow.com/q/416802/4642212). – Sebastian Simon Mar 26 '22 at 20:02
  • 1
    `Rank1` (in global scope) will forever be undefined in this code, same for the other variables with a similar name. This means `array1` will contain `undefined` four times. Please read the [documentation](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) instead of _guessing_ how JavaScript works. – Sebastian Simon Mar 26 '22 at 20:04

2 Answers2

0

In this case it is best to use reduce() on the array. Essentially your starting with an empty object and then you start iterating over the elements in your array. If the value you encounter is unknown, add the value as a property to the object as set its value i.e. its number of occurrences to 1. If you encounter a value that is already know, it must already be in the object, then get that count and increase it by one.

At the end of the loop you will have a count for each value in the array. This algorithm has a runtime complexity of O(n) which is an asymptotically optimal algorithm as the lookup in the object happens in O(1). You could also implement this with a Map, which would essentially be the same algorithm (see below).

You can think of the Map/ JS object as your different count variables rank1, rank2, rank3, .... Only difference is, it scales to however many count variables you need and you pick variable which you need to increase automatically by simply using the value that you want to count.

with JS object

const array1 = ["Rank1", "Rank1", "Rank1", "Rank3", "Rank2", "Rank4", "Rank1", "Rank3"];

const count = array1.reduce((prev, cur) => {
  if(prev.hasOwnProperty(cur)) prev[cur]++;
  else prev[cur] = 1;
  return prev;
}, {});
console.log(count);

Expected output:

{ Rank1: 4, Rank3: 2, Rank2: 1, Rank4: 1 }

with Map

const array1 = ["Rank1", "Rank1", "Rank1", "Rank3", "Rank2", "Rank4", "Rank1", "Rank3"];

const count = array1.reduce((prev, cur) => {
  if(prev.has(cur)){
    let currentCount = prev.get(cur);
    currentCount++;
    prev.set(cur, currentCount);
  } 
  else prev.set(cur, 1);
  return prev;
}, new Map());
console.log([...count.entries()]);
Expected output
[
  [
    "Rank1",
    4
  ],
  [
    "Rank3",
    2
  ],
  [
    "Rank2",
    1
  ],
  [
    "Rank4",
    1
  ]
]
Mushroomator
  • 6,516
  • 1
  • 10
  • 27
  • when i test the code alone with the array u defined it works fine but when i integrate it in my code it returns an empty array. Maybe its because the array that im passing it is empty at t=0 and gets filled through an async function, is there a way to delay the code for it to run after the array gets filled ? i hope you understood what i meant , i have been coding for only 2 month now and my synthax isnt on point at all – theo karam Mar 26 '22 at 19:31
  • Well you certainly have to wait until the array is filled which you would do by using `await` if it is an `Promise` or by using `then()`. But it's hard to tell what the problem is if I can't see it. You should certainly google for `async/ await` or `Promises`. – Mushroomator Mar 26 '22 at 19:38
  • how can i implement await or then so that the code runs after the array is filled ? i googled and read through documentation but i cant seem to find how to do it – theo karam Mar 26 '22 at 20:38
  • As I can't see your code it is impossible to help you here. What do you get when you print the array to console immediately before you try to count the occurences? – Mushroomator Mar 26 '22 at 20:47
  • i get the desired output which in this case is an array filled with Rank1 or Rank2 or Rank3 or Rank4. how can i share you my code ? – theo karam Mar 26 '22 at 20:50
  • basically what my code does is it create array1 that contains 100 elements which are determined by the value the user inputs. then the array1 is ran through another function that picks a random index of the array1 and stores it into array2, the user also inputs how many elements of the array1 will be randomly picked and pushed into the array2. once array2 is completed this is where i want to run the reduce code that will determine the occurrences of each element in array2. I hope this makes sense – theo karam Mar 26 '22 at 20:59
  • 1
    finally figured it out! i wrapped the resolve code inside an async function and created a var that awaits the array i want to resolve and passed that var to the resolve code. – theo karam Mar 26 '22 at 21:48
-2

You can try the following below code.

var rank1 = 0
var rank2 = 0
var rank3 = 0
var rank4 = 0

const array1 = ['rank1','rank1','rank1','rank3']

array1.forEach( function( item, i ) {
  
  eval( item + '+= ' + 1 + ';');
  
} );

console.log(rank1, rank3);
Mahedi Hasan
  • 178
  • 1
  • 11
  • 1
    This could potentially introduce totally unnecessary security issues if any of the values in the array is supplied by a user. The first thing that comes to my mind which would exploit that is a string like this `'while (true); const test = 1; test'` in the array. This would cause an infinite loop and thus constitute a succesful denial of service attack (DoS). And you could certainly do much worse than that if you put some effort into crafting the string. – Mushroomator Mar 26 '22 at 19:59
  • thank you for taking some time to reply. How can i modify the code to run when the array i want to loop through gets filled. the array is created by a function that i defined that only takes a number as argument. – theo karam Mar 26 '22 at 20:01