Javascript - Clarification on HashTable - javascript

I was watching a video on how to create a function to replace all duplicates in an array. For example, if an array consists of [1,1,2], the function will output simply [1,2].
After watching the video , the final code was :
let removeDuplicates = (a)=>{
let input = {};
let output = [];
for (let i = 0; i < a.length; i++){
let el = a[i];
if (!(el in input)){
input[el] = true;
output.push(el)
}
};
return output;
}
I understand majority of the function, but I'm having trouble understanding how the HashTable Input is used during the if statement.My questions are
1) how can we check if el isn't in input we input is never used previously in the function.
2) why do we set input[el] = true .
I'm sorry if this is not the clearest question in the world. I just can't get this question out of my head. Thanks in advance for the help.

input starts off empty {}, then after the 1st loop looks like {"1": true} then after the second loop, nothing has changed, after the 3rd loop looks like {"1": true, "2": true}
The code would still work even if we changed it to any of the following:
input[el] = undefined;
input[el] = null;
input[el] = el;
input[el] = "blah";
input[el] = "";
input[el] = false;
input[el] = 0;
because input contains a key "1" then the value 1 will never be added to the output array more than once. The test which handles this could also be changed from:
if (!(el in input)){
to:
if( !input.hasOwnProperty(el) ) {
See: Object.prototype.hasOwnProperty
You could also log the content of input at the end of the for loop to see what's going on like this:
console.log(JSON.stringify(input));
I've used JSON.stringify to avoid any 'helpful' browser consoles updating the content of previously logged objects.
Basically, play with the code to see what happens. If you only ever read how to code, you'll never be able to code.
Here's a snippet of the code you can run/modify to see how it works:
let a = [1, 1, 2];
let input = {};
let output = [];
console.log(JSON.stringify(input));
for (let i = 0; i < a.length; i++){
let el = a[i];
if (!(el in input)){
//if (input.hasOwnProperty(el))){
input[el] = true;
//input[el] = undefined;
//input[el] = null;
//input[el] = el;
//input[el] = "blah";
//input[el] = "";
//input[el] = false;
//input[el] = 0;
output.push(el)
}
console.log(JSON.stringify(input));
}
console.log(output);
and just for completeness you could also do away with the pseudo-hash input object by simply doing the following (although performance wise is probably much slower for big arrays):
let a = [1, 1, 2];
let output = [];
for (let i = 0; i < a.length; i++){
if (output.indexOf(a[i]) === -1 ){
output.push(a[i])
}
}
console.log(JSON.stringify(output)); // [1,2]

input is declared outside of the for loop, therefore it existed before the function and still exists inside the for loop scope throughout its course.
More info about the let keyword and its scoping.
We could set it any value we want, just so there's an el key in input

Basically, the code is using the input variable as a way to hold all the values already seen as we iterate over the passed in a array. Input starts off as empty, and gets populated as we iterate thru a. It is in scope from the perspective of the for loop.
The code sets input[el] = true, but actually you could set input[el] to anything and have the code still work. All the conditional !(el in input) is checking is that input has an object with a key of el. The value of that key does not matter in this case.
Using your example where a is [1,1,2]...
You begin with having the input object as empty.
Then, you take in the first element of a, 1, and set el = 1.
if 1 is not in input (it's not), you set input[1] = true, and push 1 onto the output array.
Next, you take in the second element 1 and set el = 1.
!(el in input) at this point is false since 1 is already in the input object. you ignore this and continue to the next element in a.
finally, you check 2 and set el = 2. if 2 is not in input (it's not), you set input[2] = true, and push 2 onto the output array.
A more straightforward way to do this is to convert the array to a set.
Or alternatively, you could just use the output array and use the indexOf method on each element of your passed in a variable to see if it already exists in output - if not, add it. otherwise continue.

Good question, other people may be asking the same thing. Actually your second question answers your first question once you understand how it works, so lets start there.
2) The first thing to understand is what we are concerned about is having the output array returned without any duplicates, so we set input[el] = true, because we want this to occur. Any value that makes it through the if check, is added to input object, then to our desired output. The input behaves similar to a HashTable or Set in this case:
1)With that understanding, we can see that input object is being declared outside of the loop but within the function, so it's entire purpose is just a container(Set) to check against, via the if check, before we add an item to our output.
This can be tested out by:
let input = {};
input["One"] = true;
console.log(input); //outputs {One: true}

Related

I have an issue with removing an object key with a for in loop

I'm using a for x in loop to check if a value is == to [] and if so remove the property using remove but it just does not seem to work.
const whosOnline = (a) => {
var obj = { online:[],
offline:[],
away:[] };
for(let i = 0; i < a.length; i++){
if(a[i].lastActivity > 10 && a[i].status == 'online'){obj.away.push(a[i].username)}
else if(a[i].status == 'offline'){obj.offline.push(a[i].username)}
else{obj.online.push(a[i].username)}
}
for(let x in obj){
console.log(obj[x])
if(obj[x] === []){delete obj[x]}}
return obj
}
you were close, however you also need to reference the array index for each object key value. Comments explaining this in the code below.
var obj = { online:[],
offline:[],
away:[] };
for(var x in obj){
if(!obj[x][0]){ // The 0 is the index inside the online array, next loop it will be the offline array and then the away array.
console.log('The array is empty');
// Do what you want to do now that it is empty
// This will continue to loop through and check the value of all the keys in the object.
}
}
console.log('done');
Good luck -
Mitch from
https://spangle.com.au
Using some debugging (simply testing if a console.log gets printed for instance) you find that your if-condition is never true.
This is because you test if an array equals a newly created empty array. This can never be the case, because objects are compared by object reference instead of value.
Instead you want to probably test to see if your array is empty by doing ‘if(obj[x].length===0)’ (or shorter: ‘if(!obj[x].length)’)

Returning null or nothing instead of empty array with array.filter

Is there a vanilla js way of returning null (or nothing) instead of an empty array[]
from Array.prototype.filter when no elements are found?
Some context:
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6)
if(itemsFound){ // always true, []===true
// do something
}
The if will always evaluate to true as filter returns an empty array[].
And an empty array is 'true' in javascript. Of course I can do,
if(itemsFound.length > 0){
// do something
}
But I think just, if(itemsFound){} is neater.
The answer would not require additional js libraries.
Additional context
Coming from an OO background, I found it quite funky that objects and functions
could be treated like Boolean. But felt it was intuitive after getting used to it.
There are times that I would forget that Array.filter returns an empty array [] when no elements are found. And [] === true. This causes unnecessary bugs.
As with the answers and feedback received of now, I don't think this question can be answered except with a new implementation of Array.filter.
With that said, the accepted answer is the closest to what I have in mind.
you can do something like this, if you just want to check if it exists or not
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6).length
console.log(itemsFound);
if(itemsFound){ // always true
// do something
}
or something like this
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6)
itemsFound = (itemsFound.length > 0 ? itemsFound : false);
console.log(itemsFound)
if(itemsFound){ // always true
// do something
}
Or something like this
Array.prototype.isEmpty = function(){
return this.length == 0;
}
let arr = [1,2,3,1,1];
arr.isEmpty();
let itemsFound = arr.filter(e=> e===6)
if(itemsFound.isEmpty()){ // always true
// do something
console.log('OK');
}
You could use the length property of an array and take the value as truthy/falsy value for the condition.
function getValues(array) {
const result = array.filter(e => e === 6);
return result.length ? result : null;
}
console.log(getValues([1, 2, 3, 1, 1]));

I would LOVE to add a value to an array please

I want to add the value "peanuts" to the bag array in Java Script. Any ideas where I'm going wrong?
var bag = [];
{
for (i=0; i<bag.length; i++) {
bag.push([i] === "peanuts");
}
}
First of all you are looping over an empty array. This loop will never iterate since the array is being defined right over it without being filled before the loop.
Second, what you're pushing into the array is in fact the result of the condition [i] === "peanuts" which if it was a valid condition, will result in a boolean value.
As #Tushar said, you should use bag.push("peanuts") to add the string "peanuts" to the array bag. So let's say your code could be like this(unless you describe what kind of condition you want inside the for loop):
var bag = [];
bag.push("peanuts");
By the way, you're using an unnecessary scope block:
var bag = [];
{ // <-- Unnecessary scope block
for (i=0; i < bag.length; i++) {
bag.push([i] === "peanuts");
}
} // <-- Unnecessary scope block
Some push() examples.
This example adds peanuts to the bag array using the push command and then checks if the element is in the array using the indexOf function. This last function will return -1 if the element is not in the array, otherwise it returns the first index position the element was found at
var bag = [];
bag.push("monkeys")
bag.push("peanuts")
bag.push("bananas")
if (bag.indexOf("peanuts") >= 0) {
document.write("Found my peanuts at index " + bag.indexOf("peanuts"))
}

Cannot set property '0' of undefined in 2d array

I know this has been asked a lot of times, but how do I fix exactly this thing?
I have a map[][] array (contains tile ids for a game) and I need to copy it to pathmap[][] array (contains just 0's and 1's, it is a path map), however when I do so..
function updatepathmap(){
pathmap = [];
var upm_x = 0;
while (upm_x < map.length){
var upm_y = 0;
while (upm_y < map[upm_x].length){
pathmap[][]
if (canPassthrough(map[upm_x][upm_y])) {
pathmap[upm_x][upm_y] = 1;
} else {
console.log(upm_x);
console.log(upm_y);
pathmap[upm_x][upm_y] = 0;
}
upm_y++;
}
upm_x++;
}
console.log(map);
console.log(pathmap);
}
..it gives me Cannot set property '0' of undefined typeerror at line pathmap[upm_x][upm_y] = 0;
Despite the foo[0][0] syntactic sugar, multi-dimensional arrays do not really exist. You merely have arrays inside other arrays. One consequence is that you cannot build the array in the same expression:
> var foo = [];
undefined
> foo[0][0] = true;
TypeError: Cannot set property '0' of undefined
You need to create parent array first:
> var foo = [];
undefined
> foo[0] = [];
[]
> foo[0][0] = true;
true
You can determine whether it exists with the usual techniques, e.g.:
> var foo = [];
undefined
> typeof foo[0]==="undefined"
true
> foo[0] = true;
true
> typeof foo[0]==="undefined"
false
I would have thought pathmap[][] was a syntax error, I'm surprised you're not seeing one.
Before you can use an array at pathmap[upm_x], you must create an array at pathmap[upm_x]:
pathmap[upm_x] = [];
This would be the first line in your outer while, so:
while (upm_x < map.length){
pathmap[upm_x] = [];
// ...
Remember that JavaScript doesn't have 2D arrays. It has arrays of arrays. pathmap = [] creates the outer array, but doesn't do anything to create arrays inside it.
Side note:
var upm_x = 0;
while (upm_x < map.length){
// ...
upm_x++;
}
is an error-prone way to write:
for (var upm_x = 0; upm_x < map.length; upm_x++){
// ...
}
If you use while, and you have any reason to use continue or you have multiple if branches, it's really easy to forget to update your looping variable. Since looping on a control variable is what for is for, it's best to use the right construct for the job.
Side note 2:
Your code is falling prey to The Horror of Implicit Globals because you don't declare pathmap. Maybe you're doing that on purpose, but I wouldn't recommend it. Declare your variable, and if you need it outside your function, have your function return it.
Side note 3:
map would make this code a lot simpler:
function updatepathmap(){
var pathmap = map.map(function(outerEntry) {
return outerEntry.map(function(innerEntry) {
return canPassthrough(innerEntry) ? 1 : 0;
});
});
console.log(map);
console.log(pathmap);
}

Weird behavior of javascript

Please see attached screenshot. See pendingApp property of Object. when I am debugging in eclipse then pendingApp show array of object, Which is correct! But when I am JSON.stringify(object) then showing me empty Array.
Please let me know reason of this behavior. I think I am not aware with any Java-Script thought/concept ?? :P :)
When I will save this Object into DB then blank array of pendingApp will be stored !!
var pending_app = [];
var new_record = {"pendingApp" : [], "installedApp" :[] };
....SOME CODE+conditions HERE....
pending_app[appId] = {'action' : action };
new_record.pendingApp = pending_app;
// create app-config data
return app_model.create(new_record); //will return promise object
It's not a weird behaviour but a common mistake of using an Array to store key-value data.
Short Answer : Use a literal Object to store these data
While you can add properties on every objects in Javascript, you cannot iterate over them with the default array mechanisms
for (var i = 0; i < array.length; i++){}
array.forEach();
Simple demonstration :
var array = [];
array["anId"] = 1;
array.length; // 0
array[4294967295] = 1; // Indice >= unsigned 32-bit Max Value
array.length; // 0
array[4294967295]; // 1
So JSON.stringify with the ECMAScript 5 Specification will use the Array mechanism to iterate over all items and will find nothing.
Unlike Objects that you can list properties with
Object.keys(array); // ["anId"]

Categories

Resources