how to implement hashmap - javascript

i use hashmap in order to store the key value pair of the map.Please suggest me if their is an alternative way to do the same using NOdejs.
var HashMap=require('hashmap');
var map=new HashMap();
map.set("amit",[1,2]);
map.set("amit",[3,4]);
console.log(map.get("amit"));
On console it print [3,4], i want [1,2,3,4].
How am i going to approach this.
if value in the value variable repeated then i also want to increase the count of the value corresponding to the same key.

You are overwriting the amit keys value every time you call set on that key. Unless there is some specific API support in hashmap, your best bet is to concatenate the previous value on every set call.
Consider:
var HashMap = require("hashmap")
var map = new HashMap()
map.set('amit', [1,2])
// Concat previous value with [3, 4]
map.set('amit', map.get('amit').concat([3,4]))
console.log(map.get('amit'))
// [1, 2, 3, 4]
You could also make an abstraction for this. The following is a simple example, you would most likely want to extend it further in a real use-case.
// concatSet('foo', [1, 2])
// concatSet('foo', [3, 4])
// console.log(map.get('foo')) => [1, 2, 3, 4]
function concatSet(key, value) {
// empty array if not exists
var prevValue = map.get(key) || []
return map.set(key, prevValue.concat(value))
}

You have to loop the map.
map.set(1, "test 1");
map.set(2, "test 2");
map.set(3, "test 3");
map.forEach(function(value, key) {
console.log(key + " : " + value);
});
https://www.npmjs.com/package/hashmap

Related

array.splice() returns the item I want to eliminate rather than the array minus the item

I'm trying to remove an item from an array using the indexOf() with splice() technique suggested. This is what's happening
let someArray: string[] = [first, second, third, fourth, fifth, sixth];
let newArray: string[] = someArray.splice(3, 1);
console.log(newArray);
//deisred result = [first, second, third, fifth, sixth]
//result I'm getting = [fourth]
That's not what virtually every article I've come across says should happen. Can someone shed light on this?
UPDATE
I discovered this problem in my code when I was only ghetting 1 result where I was expecting more and tracked it back to this point.
Because when you splice an array you are mutating it, which means you are changing the original array. You're storing the result (the element you're splicing from the array) within the "newArray" variable that you have created here. So this:
var arr = [1, 2, 3, 4];
var mine = arr.splice(1, 1);
console.log(mine);
console.log(arr);
would return the original ray minus index one if we print arr to the console, and will return [2] if we print mine to the console. To get the output you're expecting, you would have to perform a different operation such as iterating through the array and utilizing splice differently. Here is an example:
var arr = [1, 2, 3, 4];
var mine = [];
for(var i = 0; i < arr.length; i++) {
if(i !== 3) {
mine.push(arr[i]);
}
}
Now I am not mutating the original array, and I am simply pushing the elements to a new array.
But if you want to simply mutate the original array and not store the new array in some sort of variable you can simply splice the original array:
var arr = [1, 2, 3, 4];
arr.splice(3, 1);
console.log(arr);
However, if you are passing it to a function, i'd probably not mutate an array outside of the function, and i'd simply return a value and store that value in a new variable:
var arr = [1, 2, 3, 4];
function deleteIndex(ar, i) {
var a = [];
ar.forEach(function(elt, index) {
if(index === i) {
}
else {
a.push(elt);
}
});
return a;
}
var newArr = deleteIndex(arr, 3);
console.log(newArr);
This way you can delete any index, or pass a function and criteria that you would want to use to determine if an index should be deleted, without changing to top-level structure of your original array by utilizing functional programming. There are also some function in the underscore module that can help you if that's the case.

Call Array key of Map object

Does anyone knows how to directly call a array key of a Map Object.
As shown in below code, I can map.get(arr), but not map.get([0, 1, 2, 3])
const map = new Map()
const arr = [0,1,2,3]
map.set(arr, "I am some number")
map.get(arr) // "I am some number"
map.get([0,1,2,3]) // undefined
You can't. Map compares objects by object identity. [0, 1, 2, 3] !== [0, 1, 2, 3] as they are different objects, even if they hold the same data.
The nearest thing you can do is to try to convert the array to something you can compare meaningfully:
const map = new Map()
const arr = [0,1,2,3]
map.set(JSON.stringify([0, 1, 2, 3]), "I am some number")
console.log(map.get(JSON.stringify([0, 1, 2, 3])))
That's correct, you have to use the same array (as in map.get(arr)), not just an equivalent array. Key comparison is like === (except that NaN matches itself). So just like this shows false:
console.log([0, 1, 2, 3] === [0, 1, 2, 3]); // false
...using map.get([0, 1, 2, 3]) is guaranteed not to find anything, because there isn't any entry in the map keyed by that array.
Separate arrays aren't === to each other - your arr does not refer to the same array container as the [0,1,2,3] that you pass to map.get. To do something like this, you'd have to iterate over the map's keys and find the one whose values all match:
const map = new Map()
const arr = [0,1,2,3];
map.set(arr, "I am some number")
// Get a reference to the same `arr` whose key you set previously:
const arrKey = [...map.keys()].find(
key => Array.isArray(key) && JSON.stringify(key) === JSON.stringify([0, 1, 2, 3])
);
console.log(map.get(arrKey));
(but this is a pretty ugly thing to have to do - if you find yourself having to do this, usually it'd be better to use a different data structure)
You need the same object reference for getting the value from a Map.
If you like to use a starting part of the array as key, you need to get all keys from the map and check against with the new array.
var map = new Map,
key0 = [0, 1, 2, 3],
key1 = [0, 1, 2, 3];
map.set(key0, "I am some number");
console.log(map.get(key0)); // "I am some number"
for (let key of map.keys())
if (key.join('|') === key1.join('|'))
console.log(map.get(key));

why does the first console.log() print undefined values but second one has transformed values

Why does the first console.log() print undefined values but second one has transformed values? I know it has to do something with function scope but not getting it
var array = [1,2,3,4,5,7];
function incrementByOne(arr) {
arr = arr.map(function(value, index, array){
arr[index] = arr[index] +1;
});
console.log(arr);
}
incrementByOne(array);
console.log(array);
// [undefined, undefined, undefined, undefined, undefined, undefined]
// [2, 3, 4, 5, 6, 8]
also i notice that the first console.log() knows how many times to iterate but what happens to the value...
js bin link
you need to return the incremented value from the function inside map. use return arr[index] +1
Also you need to return the new array formed using map and stored in arr now.
var array = [1,2,3,4,5,7];
function incrementByOne(arr) { //contains array reference
arr = arr.map(function(value, index, array){
return value +1;
});
//now arr contains a new array and doesn't refer to passed array anymore.
console.log(arr);
return arr;
}
array = incrementByOne(array);
console.log(array);
// [undefined, undefined, undefined, undefined, undefined, undefined]
// [2, 3, 4, 5, 6, 8]
if you don't want to return, you can use forEach(), as in that case arr will refer to passed array throughout. The difference is because map returns a new array.
var array = [1,2,3,4,5,7];
function incrementByOne(arr) { //contains array reference
arr.forEach(function(value, index){
arr[index] = value +1;
});
//arr still refers to the passed array.
console.log(arr);
}
incrementByOne(array);
console.log(array);
// [undefined, undefined, undefined, undefined, undefined, undefined]
// [2, 3, 4, 5, 6, 8]
Well, all the above answers are correct but they miss the most important point here. There is a concept in JavaScript called call by sharing.
Consider this code:
var num= 3;
var json = {myValue : '10'};
var json2 = {myValue : '100'};
function callBySharing(a,b,c){
a = a + 37;
b = {myValue : 'new value'};
c.myValue = 'new Value';
}
callBySharing(num,json,json2);
console.log(num);//3 *UNCHANGED*
console.log(json.myValue);//10 *UNCHANGED*
console.log(json2.myValue);//'new Value' *CHANGED*
So what you are doing is same as what is happening in json.myvalue; You are trying to update the whole object and replace it with the new value. So a very simple change in the code with do this for you:
var array = [1,2,3,4,5,7];
function incrementByOne(arr) {
arr.map(function(value, index, array){
arr[index] = arr[index] +1;
});
console.log(arr);
}
incrementByOne(array);
console.log(array);
I just replaced the arr= arr.map().... part to just arr.map().....
What this does is, it changes the function to json2.myValue example case.
So what is the difference between the 2: JS lets you update items within the object but not the whole object.By making the above said change in code, you are updating individual values of arr and not replacing the whole object with new values. I learnt this concept from SO only back when I was confused with it. So I am linking the post(Is JavaScript a pass-by-reference or pass-by-value language?)
Hope this helps!
var array = [1,2,3,4,5,7];
function incrementByOne(arr) {
arr = arr.map(v => v + 1);
console.log(arr);
}
incrementByOne(array);
console.log(array);
// [undefined, undefined, undefined, undefined, undefined, undefined]
// [2, 3, 4, 5, 6, 8]
A couple of things going on here:
The callback you pass into the .map function should return a value with the return keyword. If you don't return a value from the callback, the default return value is undefined. That's why the 'arr' array you define in incrementByOne only has undefined values inside of it when you log it with your first console.log. I think what you're really trying to do is simply return value + 1 inside of the callback.
You're making a classic passed-by-value passed-by-reference error here; it's a mistake everyone makes when they're first learning JS. I'd recommend checking out posts like this one. In short, inside of your .map callback you are mutating the array that you passed into incrementByOne, which is the same array you log out with the second console.log; that's why the values appear to have been incremented correctly.

creating a new arrays from a existing array of arrays

How can I create a new array without doing for each? The new array should be as follows
labels : ["Direct", "Organic Search", "Referral"]
any suggestion using javascript?
Ok. Don't want Array.forEach()? Try using Array.map function with ES6 arrow function expression for such case:
// supposing arr is your initial array
var labels = arr.map((v) => v[0]);
console.log(labels); // ["Direct", "Organic Search", "Referral"]
It's not possible to do this without any kind of loop, but as you're suggesting, a manual iteration like a foreach isn't what you're looking for, indeed.
Array.prototype.map() is the function you need in this case. ("under the hood", it's still a loop)
Here's how you can use map to get your desired result:
var myArray = [["a", 1, 2], ["b", 3, 4], ["c", 5, 6]];
var result = myArray.map(function(current){ // For each item in `myArray`
return current[0]; // return it's first element.
}); // And use that in `result`.
console.log(result)
Note that myArray.map does not change the value of myArray. You'll need to store the returned value from .map somewhere.
If you don't need to worry about supporting anything but the latest browsers, you can make this slightly shorter, using ES6:
var myArray = [["a", 1, 2], ["b", 3, 4], ["c", 5, 6]];
var result = myArray.map((c) => c[0]);
console.log(result)
You can try following
var arr1 = []; // your main array
var labels = arr1.map(function(item){
return item[0];
});
For reference, map

Using lodash push to an array only if value doesn't exist?

I'm trying to make an array that if a value doesn't exist then it is added but however if the value is there I would like to remove that value from the array as well.
Feels like Lodash should be able to do something like this.
I'm interested in your best practises suggestions.
Also it is worth pointing out that I am using Angular.js
* Update *
if (!_.includes(scope.index, val)) {
scope.index.push(val);
} else {
_.remove(scope.index, val);
}
You can use _.union
_.union(scope.index, [val]);
The Set feature introduced by ES6 would do exactly that.
var s = new Set();
// Adding alues
s.add('hello');
s.add('world');
s.add('hello'); // already exists
// Removing values
s.delete('world');
var array = Array.from(s);
Or if you want to keep using regular Arrays
function add(array, value) {
if (array.indexOf(value) === -1) {
array.push(value);
}
}
function remove(array, value) {
var index = array.indexOf(value);
if (index !== -1) {
array.splice(index, 1);
}
}
Using vanilla JS over Lodash is a good practice. It removes a dependency, forces you to understand your code, and often is more performant.
Perhaps _.pull() can help:
var _ = require('lodash');
function knock(arr,val){
if(arr.length === _.pull(arr,val).length){
arr.push(val);
}
return arr;
}
Mutates the existing array, removes duplicates as well:
> var arr = [1,2,3,4,4,5];
> knock(arr,4);
[ 1, 2, 3, 5 ]
> knock(arr,6);
[ 1, 2, 3, 5, 6 ]
> knock(arr,6);
[ 1, 2, 3, 5 ]
Use includes function to check that item is exists in array, and remove to delete existing item.
function addOrRemove(arr, val) {
if (!_.includes(arr, val)) {
arr.push(val);
} else {
_.remove(arr, item => item === val);
}
console.log(arr);
}
var arr = [1, 2, 3];
addOrRemove(arr, 1); // arr = [2, 3]
addOrRemove(arr, 4); // arr = [2, 3, 4]
addOrRemove(arr, 2); // arr = [3, 4]
<script src="https://raw.githubusercontent.com/lodash/lodash/4.11.2/dist/lodash.min.js"></script>
In this case you can use 'concat' to push and 'uniq' to validate unique values:
example:
var ar = [1, 2, 3, 1, 5, 2, 4]
ar = _.uniq(_.concat(ar, 9))
//[1, 2, 3, 5, 4, 9]
e.g.: https://codepen.io/dieterich/pen/xeZNJY
ref.: https://lodash.com/docs/4.17.11#uniq
This single liner should do the job. If element to be inserted does not exist, it inserts the element and returns the length of the resulting array. If element exists in the array it deletes the element and returns the deleted element in a separate array.
var arr = [1,2,3,4,5],
aod = (a,e,i=0) => !!~(i = a.indexOf(e)) ? a.splice(i,1) : a.push(e);
document.write("<pre>" + JSON.stringify(aod(arr,6)) + JSON.stringify(arr) + "</pre>");
document.write("<pre>" + JSON.stringify(aod(arr,6)) + JSON.stringify(arr) + "</pre>");
Well actually i hate push since it returns the resulting array length value which is most of the time useless. I would prefer to have a reference to the resulting array to be returned so that you can chain the functions. Accordingly a simple way to achieve it is;
var arr = [1,2,3,4,5],
aod = (a,e,i=0) => !!~(i = a.indexOf(e)) ? a.splice(i,1) : (a.push(e),a);
document.write("<pre>" + JSON.stringify(aod(arr,6)) + JSON.stringify(arr) + "</pre>");
document.write("<pre>" + JSON.stringify(aod(arr,6)) + JSON.stringify(arr) + "</pre>");
So now this is reasonably chainable.
If you don't need to support IE, or if you are using polyfills, you can use Array.prototype.includes()
const addUniq = (array, value) => array.includes(value)
? array.length
: array.push(value);
The simplest way to do this is use _.isEmpty and _.remove Lodash functions:
if (_.isEmpty(_.remove(array, value)) {
array.push(value);
}
After remove function will be return removed values or an empty array, and if return an empty array then we will add a new value.
It's an old question but what you are looking for is XOR Lodash xor
It adds the value if is not already there and removes it otherwise. Great for toggle use-cases.

Categories