-3

I was searching for a way to return the mode of an array when I found this answer:

var store = ['1','2','2','3','4'];
var frequency = {};  // array of frequency.
var max = 0;  // holds the max frequency.
var result;   // holds the max frequency element.
for(var v in store) {
    frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency.
    if(frequency[store[v]] > max) { // is this frequency > max so far ?
            max = frequency[store[v]];  // update max.
            result = store[v];          // update result.
    }
}

This block of code works perfectly, and I understand it well enough that I was able to output both the most common value and the amount of times that value appeared. However, this code block makes no sense to me at all. Specifically the line:

frequency[store[v]]=(frequency[store[v]] || 0)+1;

I'd thought that frequency was an array, with store[v] serving as the index. What exactly is happening in this code block?

Space Ostrich
  • 413
  • 3
  • 5
  • 13
  • [JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript) has all you need and `frequency` isn't an [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) it's an [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) – Andreas Apr 11 '16 at 05:44
  • 1
    *"I need a comprehensive breakdown of everything"* - sounds like a boss. Not good. – T J Apr 11 '16 at 05:44
  • The frequency variable is an object, which in some languages is called an associative array. That might be where your confusion lies. The frequency object is used as a histogram – paulski Apr 11 '16 at 05:45
  • You need to ask specific questions if you are stuck somewhere. If you want a review of the code, please see http://codereview.stackexchange.com/ – Rohit Agre Apr 11 '16 at 05:46
  • does frequency have any parameters? The [] threw me off, thinking of it as an object is clearing things up a little bit, I can feel it about to slip into place, but I'm still just short of getting it. – Space Ostrich Apr 11 '16 at 05:53
  • I'd normally be less clinical in asking this sort of question but I've consistently found that people seem to want a no frills question. Hence the "I need a comprehensive breakdown of everything" as opposed to my preferred "Could somebody please help me understand this?". – Space Ostrich Apr 11 '16 at 05:59
  • @RohitAgre You are correct that Stack Overflow requires questions to be about a specific problem. However, Code Review is not appropriate for this question either, since asking for explanations of how code works is off-topic there. – 200_success Apr 11 '16 at 06:26
  • Question has been renamed and reformatted to make it more useful to others with a similar problem. I'm not sure on the name of the question, I'd like to incorporate "[ ]" into the title somewhere, as the brackets were the crux of the confusion and are likely to be involved in future searches on the subject. I'd greatly appreciate some alternate name suggestions. – Space Ostrich Apr 11 '16 at 06:51

3 Answers3

2

Does this work for you?

for(var v in store) {
    numberWeAreLookingAt = store[v];

    // we hadn't gone through this number yet, so it's not defined 
    // as a property in the object "frequency"
    if(frequency[numberWeAreLookingAt] === undefined)
      frequency[numberWeAreLookingAt] = 0; // let's initialize that property with the 
                                           // number zero, in it we will hold the
                                           // number of times it appeared

    // Sum 1 to the times it appeared already (or zero if we 
    // initialized it on the "if" above)
    frequency[numberWeAreLookingAt] = frequency[numberWeAreLookingAt] + 1;

    // the times this number appeared is more than "max"?
    if(frequency[numberWeAreLookingAt] > max) {
        // then now "max" is the times this number appeared
        max = frequency[numberWeAreLookingAt];
        // and the result is this number
        result = numberWeAreLookingAt;
    }
}

Note that the code in your question is perfectly readable. If you really can't read it, you can't "blame it on the programmer": you just don't understand code very well and should work on that.

"Making code readable" doesn't mean making it verbose... it means "make it obvious on a first read to whoever knows the syntax", and I think the code in your question fits that properly. My code is extremely verbose and my comments should be unneeded: they are just explaining what the next line of code does

The only line of code that "may" need explanation is:

frequency[store[v]]=(frequency[store[v]] || 0)+1;

And you can see it's decomposition above... x = (x || 0)+1 means get x if it's defined, or 0 if it's not: then add 1 and assign back to x, which is what I did on verbose form in my code.

Other thing that seems to confuse the OP (as noted in the comments), is using the brackets syntax to access an object properties. This is not uncommon in dynamically executed languages (and I'd argue that, taking how object prototypes are done in javascript, the brackets syntax makes more sense than the dot syntax, but that's just an oppinion).

In Javascript, you can access object properties with two different syntaxes: object.property is equivalent to object[property]. The main difference is that when using the brackets syntax you can use expression to evaluate the property name (or use other variables, as we are doing here). In C#, for example, you could do the same using dynamic and ExpandoObject.

Note that while this may confuse you, it's not really that important for the question... you could also think of frequency being an array where the indexers are objects, instead of a sequential number, and it'd work the same (in PHP, for example, you could achieve this using keyed arrays, or a Dictionary in C#, and it's a very typical pattern in functional languages).

Jcl
  • 27,696
  • 5
  • 61
  • 92
  • 2
    +1 for the last paragraph. A rewrite does not seem necessary and the original code was already commented verbosely IMO. – Paul Apr 11 '16 at 05:58
  • 1
    I'm not even a javascript coder, and I understood it perfectly fine :-) – Jcl Apr 11 '16 at 05:59
  • I get how store[v] is the number we're looking at. What I don't get is how frequency[store[v]] is the number of times that v has appeared. There's some part of this that I'm not seeing. – Space Ostrich Apr 11 '16 at 06:11
  • 1
    @SpaceOstrich every iteration of the loop, `frequency[store[v]]` is incremented... so if you have 5 numbers in `store`, the loop does 5 iterations. On the first iteration, if `store[0]` is `1`, then `frequency[1] = 1`, in the second iteration, if `store[1]` is `1` again, then `frequency[1]` gets incremented (now `frequency[1]` is `2`), and so on... – Jcl Apr 11 '16 at 06:21
  • I think I get it. frequency[store[v]] is a parameter, such as frequency.1. My confusion is from the fact that object[parameter] is not how I'd expect a parameter to be formatted. I'm used to the more common object.parameter. That, combined with the mention of a frequency array earlier, and the compact nature of the code, had me quite confused. – Space Ostrich Apr 11 '16 at 06:33
  • 1
    @SpaceOstrich You can't do this in a similar way without using bracket notation. Dot notation requires you to know the property names at the time you write the code. Bracket notation evaluates the expression in the brackets to dynamically determine the property name. – Paul Apr 11 '16 at 06:34
  • 1
    @SpaceOstrich `object[ 'x' ]` is the same as `object.x`, but the bracket notation is more powerful, because it can evaluate an expression like `object[ 'x' + i ]` or `object[ store[v] ]`, which you can't do in dot notation. – Paul Apr 11 '16 at 06:37
  • Right, yeah, now that I think of it, I've seen this kind of parameter notation before. If Jcl could add a quick line explaining that bracket notation is being used and what that is, I can flag that as the correct answer. – Space Ostrich Apr 11 '16 at 06:38
  • 1
    I'm driving now. Will do in 15 minutes – Jcl Apr 11 '16 at 06:39
  • I've reformatted the question to make it more useful to others, I'd appreciate any suggestions on how to improve the formatting and name of the question to make it as useful as possible to others with similar problems in future. – Space Ostrich Apr 11 '16 at 06:53
  • 2
    I added a small explanation of the brackets vs dot syntax. I don't think it's really important for the question (and I've observed that in the explanation), but there you go – Jcl Apr 11 '16 at 07:05
1

frequency is not an array. It is an object, which is a map of keys to values. In this case the keys are strings from your store array and the values are the frequencies those strings occur. One of the easiest ways to see what is going on would be to add a couple of console.logs:

var store = ['1','2','2','3','4'];
var frequency = {};  // array of frequency.
var max = 0;  // holds the max frequency.
var result;   // holds the max frequency element.
for(var v in store) {
    frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency.
    console.log( frequency );
    if(frequency[store[v]] > max) { // is this frequency > max so far ?
            max = frequency[store[v]];  // update max.
            console.log( 'Found new max!', max + ' occurrences of \'' + store[v] + '\'' );
            result = store[v];          // update result.
    }
}

Run that and take a look at the console to see what the frequency object contains after each iteration. This is what I get it Chrome:

Object {1: 1}
Found new max! 1 occurrences of '1'
Object {1: 1, 2: 1}
Object {1: 1, 2: 2}
Found new max! 2 occurrences of '2'
Object {1: 1, 2: 2, 3: 1}
Object {1: 1, 2: 2, 3: 1, 4: 1}

frequency[store[v]]=(frequency[store[v]] || 0)+1; is a shorthand for:

 if (frequency[store[v]]) {
     frequency[store[v]]++;
 } else {
     frequency[store[v]] = 1;
 }

That is because the || operator in JavaScript returns its left operand if it is truthy and its right operand otherwise, so the expression frequency[store[v]] || 0 evaluates to 0 when frequency[store[v]] is undefined (since undefined is falsy), but once frequency[store[v]] is 1 or greater it evaluates to the value of frequency[store[v]].

Paul
  • 139,544
  • 27
  • 275
  • 264
1

First, skim through this tutorial to understand the differences between a Javascript array and a Javascript object. Then you'd read the code like this:

var store = ['1','2','2','3','4'];               // store[0] == '1', store[1] = '2', etc.
var frequency = {};  // array of frequency.      // frequency.'1' = undefined

Then, when the assignment happens, it's easier to understand. frequency[store[v]] is just simply frequency.'1' where v == 0, meaning you're accessing the object frequency and its field named by the string 1. A javascript object can have fields named anything, e.g. frequency.'apple', frequency.'table', etc. They're just undefined until you give them value.

The assignment, then, is easier to read

if (frequency.'1' is undefined)
    store the value [0 + 1] into frequency.'1'
else increment the value by 1
Kafeaulait
  • 664
  • 1
  • 6
  • 14
  • So frequency[store[v]] is roughly analogous to a more traditional "object.parameter", with the contents of the [] serving as what would come after the '.'? Or to put it another way, "frequency[store[v]]" is roughly equal to "frequency.firstValue", and then, "frequency.secondValue", and so on? – Space Ostrich Apr 11 '16 at 06:23
  • @SpaceOstrich yes, the `[]` operator is just another way of accessing the properties of a js object. You got the idea correctly. – Kafeaulait Apr 11 '16 at 16:11