3

Please consider this JS function

I have seen this similar question but couldn't understand.

function a (ResultArray){
    var counts={};
    for ( p = 0; p < ResultArray.length; p++){            
        counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;            
    }
    return counts;
}

var arr = ["a","b","c","d","a","b","e"];        
var res = new a(arr);
console.log(res)

Its working fine and giving the count. I need to understand how is it giving the count, specially (counts[ResultArray[p]] + 1) || 1; part. what is +1 and || doing.

Roberto Russo
  • 834
  • 10
  • 22
user1207289
  • 3,060
  • 6
  • 30
  • 66
  • 2
    It looks like it's attempting to increment the value for a particular key, then if that fails (because the key doesn't exist), it sets it to `1`. --- Honestly, it's a pretty strange looking line of code. – byxor Jul 06 '17 at 15:32
  • 4
    `+ 1` is adding 1 to `counts[ResultArray[p]]` and `||` is a truthy check: if `counts[ResultArray[p]] + 1` is `NaN, undefined, null, or 0` the expression will evaluate to `1` see [this](https://stackoverflow.com/questions/476436/is-there-a-null-coalescing-operator-in-javascript) post for greater detail – Patrick Barr Jul 06 '17 at 15:33
  • @Patrick Barr , thats what I am trying to understand , what is it achieving by adding 1, or what is it checking by adding 1. Is it checking the next value? If it is , then how is it keeping track of previously found values and then incrementing them. Its too confusing for me – user1207289 Jul 06 '17 at 15:53
  • array.length-(new Set(array)).length would work too... – Jonas Wilms Jul 06 '17 at 15:54
  • 1
    @user1207289 It's keeping track of how many times something appears in the array with an object who's keys are the values in the array, so it's just adding 1 to the count of that value, and at the end the object will have the counts of each duplicate – Patrick Barr Jul 06 '17 at 16:00

3 Answers3

3

I guess the main confusion comes from this line:

counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;

The || operator returns what is on the left side if it is "truthy" (anything other than the "falsy" values false, 0, '', null, undefined, and NaN), otherwise it returns what is on the right hand side.

If ResultArray[p] is not inside of counts, then counts[ResultArray[p]] will be undefined. Since undefined + 1 is NaN, the left hand side of || is "falsy", so it will return the right hand side 1.

Otherwise, counts[ResultArray[p]] will be the amount of times we've already seen ResultArray[p], and we'll add 1 to it. In this case the left hand side will be "truthy" and it will return the new count.

Peter Olson
  • 139,199
  • 49
  • 202
  • 242
  • I am even more confused 1) how come `counts[ResultArray[p]]` is amount of times and not `"a"` when this `var counts={};counts["a"]=1;counts["b"]=2;console.log(counts["a"]);` prints `1`. 2) lets say , I understand the issue in 1 , when `ResultArray[p]` is not in `counts` and it returns `1`, does that mean it increments by `1` or that iteration is not counted. – user1207289 Jul 06 '17 at 17:14
  • Please disregard 1) above, I understand that `counts[ResultArray[p]]` is the value of `"a"` and not `"a"` – user1207289 Jul 06 '17 at 17:34
  • 1
    @user1207289 Suppose `ResultArray[p]` is `"a"`, and `"a"` is not in `counts`. Then `counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1` is the same as `counts["a"] = (counts["a"] + 1) || 1`, which is the same as `counts["a"] = (undefined + 1) || 1`, which is the same as `counts["a"] = NaN || 1`, which finally is the same as `counts["a"] = 1`. That is, the first time we encounter `"a"`, we set `counts["a"]` to `1`. – Peter Olson Jul 06 '17 at 18:41
  • I think reading it this way makes it better for me to understand, just sharing it here, in case anyone needs it. when an element is encountered,the particular line in question is evaluated as `value of key = (previous value of key +1) || 1` and since for each key value is `undefined` when the key is encountered first time the line is evaluated as `value of key = (undefined +1) || 1` – user1207289 Jul 07 '17 at 16:45
1

The array value hasn't been set yet, so you can't increment undefined. The first time it hits a value, the "|| 1" portion sets the initial value to 1. If it hits that same index again (which is no longer undefined and now set to 1), it executes the left side instead and increments the pre-existing value by 1.

ebraley
  • 206
  • 1
  • 9
0

there are some things to keep in mind in the above algorithm

  1. javascript objects are represented by sets, dictionary hence counts = {} is just a set or dict hence counts."a" or counts.a or counts[a] can all be used to access the value inside of counts object therefore counts.a = 1 or counts["a"] = null is an assignment to counts set (object).
  2. javascript dynamically allocates variables hence counts[ResultArray[p]] sincecountsis a object javascript dynamically creates the value of ResultArray[p]]as a property or key tocounts` as javascript is loosely typed
  3. evaluations start from left to right on the line counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1; javascript start evaluating starting from count[ResultArray[p]] where counts evaluates to an object (set, dictionary) then it moves to ResultArray which evaluates to array during runtime p is then evaluated to a number say 0 in first iteration hence the whole evaluation is counts[ResultArray[0]] where javascript creates the key counts.a or counts."a" and assigns to it undefined evaluation then continues to (counts[ResultArray[p]] + 1) || 1; and inside of it counts[ResultArray[p]] since it had already done in previous step that evaluates to counts.a or counts."a" = undefined then moves to undefined + this should look like this after left right evaluation (undefined + 1) javascript then evaluates that to NaN in the next step of evaluation
    '(NaN)|| 1 whereNaNis always false but 1 is always true in javascript and true = 1 false = 0 hence 1 is assigned tocounts.aorcounts."a" or counts[a] = 1

here is javascript evaluation steps from left to right broken down counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;

  1. counts = {} (object,set or dict) in javascript
  2. ResultArray (array)
  3. p (integer)
  4. ResultArray[p] = "a" in first iteration
  5. counts["a"] (undefined is assigned since there was no previous assignement)
  6. = (assignment operator)
  7. counts = {} (object,set or dict) in javascript
  8. ResultArray (array)
  9. p (integer)
  10. ResultArray[p] = "a" in first iteration
  11. counts["a"] (undefined)
  12. + (addition operation)
  13. 1 (integer)
  14. counts["a"] + 1 = undefined + 1 = NaN
  15. NaN || 1 = 1 (boolean 1 = true false = 0 Nan = 0 = false 0 || 1 1 wins in or statement)
  16. counts["a"] = 0 || 1 (1 is assigned to counts["a"])
sachgits
  • 345
  • 3
  • 14