learninjs
learninjs

Reputation: 89

Javascript hash table data structure. Intersection&reduce

The question was when given multiple arrays return an array with all intersected array values. I have read through a few solutions and I am trying to understand this hash table solution.

I am having trouble understanding this line:

a[propName] = a[propName] || {count:0, value: val};   

To my understanding we are looping through each element of our subarray. Our accumulator object is given the property name of the subarrays value.

This is where I get confused. The value of our object property is a[propName]. I do not understand this value. My understanding is we should make our object property the value of our subarray (making the line a[propName]=a[propName] into a[propName]=propName instead) but when I do this we are not able to count how many times the property has occurred. I do not get why we have to put the a[propName] and what data structure we are accessing that is different from just using propName. There obviously a difference since when I use a[propName] we are able to count how many times the property has occurred. If someone can thoroughly explain what is going on I'd be very grateful.

function intersection(){
  // convert arguments to array of arrays
  var arrays = [].slice.call(arguments);
  // create an object that tracks counts of instances and is type specific
  // so numbers and strings would not be counted as same
  var counts= arrays.reduce(function(a,c){
     // iterate sub array and count element instances
     c.forEach(function(val){
        var propName =  typeof val + '|' + val;
        // if array value not previously encountered add a new property        
        a[propName] = a[propName] || {count:0, value: val};       
        // increment count for that property
        a[propName].count++;
        console.log(a);
     });
     return a;
  },{});

  // iterate above object to return array of values where count matches total arrays length
  return Object.keys(counts).reduce(function(resArr, propName){
    if(counts[propName].count === arrays.length){
      resArr.push(counts[propName].value);
    }
    return resArr;
  },[]);

}

Upvotes: 2

Views: 93

Answers (1)

rpadovani
rpadovani

Reputation: 7360

The line you are pointing checks if a[propName] exists, and, if it not exists (so it is undefined) initialize it to {count:0, value: val};.

Let's have a closer look.

First of all, let's use more meaningful names. a is accumulator, the variable you use to keep track of everything.

At the beginning, it is an empty object.

At the first iteration of c.forEach it has no properties.

Therefore, given a propName like 'string|asd', it adds its first property, and accumulator becomes accumulator = {'string|asd' : {count:0, value: val}};.

Then increments the value of count.

If it finds another 'string|asd' it just increments the count, because the check a[propName] = a[propName] || {count:0, value: val}; will just keep the prop.

let a = {}

// a.c does not exist, therefore is undefined
console.log(a.c)

a.c = a.b || 1;
// a.c now is 1
console.log(a.c)

a.c = a.c || 2;
// a.c is still 1, because the `or` operator returns as soon as it finds a valid value
console.log(a.c)

Upvotes: 1

Related Questions