Iterating and enumerating an array, not getting same results - javascript

I have to pass a test on this line of code and after reading various posts about making sure that I am iterating an array and not enumerating to try and avoid possible complications with prototype chaining etc. (to be honest I don't understand everything however I am getting there).
I have two pieces of code that appear to be doing the same thing, just one is enumerating and one is iterating. However, the part that has me pulling my hair out is that if I enumerate then I pass all the tests but if I iterate then I don't, I fail the part that says "should copy properties from source to destination"
Here is the iteration:
function copy(destination, source){
var index;
for (index = 0; index <= source.length; index++) {
if (source.propertyIsEnumerable(index) && destination[index] === undefined) {
destination[index] = source[index];
}
}
return destination;
I am passing the second argument in a function called "source" to the first function called "destination".
now when I put the enumeration code in I pass all tests:
function copy(destination, source){
var index;
for (var index in source) {
if (source.propertyIsEnumerable(index) && destination[index] === undefined)
destination[index] = source[index];
}
return destination;
};
Now I believe they are doing the same thing however it would appear that they aren't?

The iteration version fails on an example like this. Both versions copy the indexed elements, but only the enumeration version copies named properties of the array object.
var oldArray = [1, 2, , 4];
oldArray.someProp = "foo";
var newArray1 = copyArrayIter(oldArray);
console.log(newArray1);
console.log(newArray1.someProp);
var newArray2 = copyArrayEnum(oldArray);
console.log(newArray2);
console.log(newArray2.someProp);
function copyArrayIter(source) {
var index;
var destination = [];
for (index = 0; index <= source.length; index++) {
if (source.propertyIsEnumerable(index) && destination[index] === undefined) {
destination[index] = source[index];
}
}
return destination;
}
function copyArrayEnum(source) {
var index;
var destination = [];
for (var index in source) {
if (source.propertyIsEnumerable(index) && destination[index] === undefined)
destination[index] = source[index];
}
return destination;
};
It will copy the elements at indexes 0, 1, and 3, but it won't copy the someProp property.

Related

I can not understand this code

I had to remove same data in array.
I found this code and its work exactly the way i want but I can not understand part of this code.
please explain this code and WHAT IS THIS >>> a[this[i]] <<<
Array.prototype.unique = function() {
var a = {}; //new Object
for (var i = 0; i < this.length; i++) {
if (typeof a[this[i]] == 'undefined') {
a[this[i]] = 1;
}
}
this.length = 0; //clear the array
for (var i in a) {
this[this.length] = i;
}
return this;
};
Please see the comments before each line that explain that line of code
//added unique function to prototype of array so that all array can have unique //function access
Array.prototype.unique = function() {
//creating a temp object which will hold array values as keys and
//value as "1" to mark that key exists
var a = {}; //new Object
//this points to the array on which you have called unique function so
//if arr = [1,2,3,4] and you call arr.unique() "this" will point to
//arr in below code iterating over each item in array
for (var i = 0; i < this.length; i++) {
//idea is to take the value from array and add that as key in a so
//that next time it is defined. this[i] points to the array item at
//that index(value of i) //and a[this[i]] is adding a property on a
//with name "this[i]" which is the value //at that index so if value
//at that index is lets say 2 then a[this[i]] is //referring to
//a["2"].thus if 2 exists again at next index you do not add it to a
//again as it is defined
if (typeof a[this[i]] == 'undefined') {
a[this[i]] = 1;
}
}
this.length = 0; //clear the array
//now in a the properties are unique array items you are just looping
//over those props and adding it into current array(this) in which
//length will increase every //time you put a value
for (var i in a) {
this[this.length] = i;
}
//at the end returning this which is the modified array
return this;
};
//Edit
stored value of a[this[i]] is 1 for all the keys in a it will be one.
you start with
arr = [1,2,3,2,3,4];
when you call arr.unique
the code in the first loop creates a something like this
a = {
"1":1,
"2":1,
"3":1,
"4":1
}
so you can see that only unique values are as properties in a.
Now in the for-in loop you are just taking the keys of a(ie 1,2,3,4) and adding it to the array(this).
Hope this helps let me know if you need more details
a[this[i]] =>
this[i] -> get i element from current object, in this case it's Array.
a[] -> get element from var a at position specified in [], in this case what value is inside this[i]

return object if list<object> value is exists (Javascript, jquery grep/map)

I'm using grep and map functions to get the object if the value is exists in the list, but it does not work well.
I have a list customList and the customObject has the int id property and List value properties.
customobject[0].id
customObject[0].value[]
What I want is check if in the List the value 5 exists.
The function what I'm using is:
var gettedcustomObject = $.grep(customList, function (e) {
var result = e.Value.map(function (a) { return a === 5;});
return result;
});
What am I doing wrong and what is the correct implementation?
Note: 2x foreach could be a solution, but customList has more than 1000 objects with 10000 values. I think that slow down the proces.
This should do it.
var gettedcustomObject = customList.filter(function(v){
var ln = v.Value.length;
for(var i = 0; i < ln; i++){
if(v.Value[i] == 5){
return true;
}
}
return false;
// Or simply:
// return v.Value.indexOf(5) != -1;
});
This will work if v.Value is an array.
You should look at some: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
Way faster than the other methods like filter, map or sort as it was designed for this.
//List to work against
var arr = [];
//Populate
while (arr.length < 9999999) {
arr.push(Math.random() * 999999)
}
//Set element to find
arr[10] = "test";
//Begin timing
var d = new Date().getTime();
//Run filter
console.log(arr.filter(function(a){return a === "test"}).length > 0);
//How long did it take
console.log("`filter` took:",new Date().getTime() - d,"ms")
//Begin timing
d = new Date().getTime();
//Run filter
console.log(arr.some(function(a){return a === "test"}));
//How long did it take
console.log("`some` took:",new Date().getTime() - d,"ms")
<script>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function(fun/*, thisArg*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
}
</script>
If your goal is to find the first object in the list that contains 5 in the Value property, then you're looking for Array#find and Array#indexOf:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
Note that Array#find was added relatively recently and so you may need a polyfill for it (which is trivial). MDN has one.
Or you could use Array#includes instead of indexOf, which will be in ES2017 and is also polyfillable:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.includes(5);
});
Live Example (using indexOf):
var customList = [
{
note: "I'm not a match",
Value: [2, 3, 4]
},
{
note: "I'm not a match either",
Value: [78, 4, 27]
},
{
note: "I'm a match",
Value: [889, 5, 27]
},
{
note: "I'm also a match, but you won't find me",
Value: [4, 6, 5]
}
];
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
console.log(gettedcustomObject);
If your logic matching the item inside Value were more complicated, you'd use Array#some and a callback function rathe than indexOf. But when looking to see if an array for an entry in an array based on ===, indexOf or the new Array#includes are the way to go.
one approach using Array.some() and Array.indexOf(). some loop break once the element is found
var gettedcustomObject;
customobject.some(function(obj){
if(obj.value.indexOf(5) >-1){
gettedcustomObject = obj;
return true;
}
});

Javascript Searching Array for partial string

Have a function that returns an array of objects. The array has a rate object that has a name field. Inside the name field are names such as "Slow speed" and "Fast speed".
I have written the following in hopes to create a new array that will filter out the array values and just return only those with "Slow" that matches from the rates[i].name.
So far I am encountering this error in my dev console.
"Uncaught TypeError: value.substring is not a function"
var rates = myArray();
var index, value, result;
var newArr = [];
for (index = 0; index < rates.length; ++index) {
//value = rates[index];
if (value.substring(0, 5) === "Stand") {
result = value;
newArr.push();
break;
}
}
Part of array return in console.
"rates":[{"id":1123,"price":"1.99","name":"Slow speed - Red Car","policy":{"durqty":1,"durtype":"D","spdup":15000,"spddwn":15000}
You have an object at each array location not the string itself, try this instead:
var rates = myArray();
var index, value, result;
var newArr = [];
for (index = 0; index < rates.length; ++index) {
name = rates[index].name;
if (name.substring(0, 4) === "Slow") {
newArr.push(rates[index]);
}
}
Try using filter function like this, it is much more cleaner to see
var newArr = rates.filter(function(rate){
return rate.name && rate.name.substring(0,4) === "Slow";
});
You can use filter to do this, for example:
var newArr = rates.filter(function(val){
// check if this object has a property `name` and this property's value starts with `Slow`.
return val.name && val.name.indexOf("Slow") == 0;
});
As #4castle mentioned, instead of indexOf(...) you can use slice(...) which may be more efficent, eg: val.name.slice(0,4) == "Slow"

JavaScript Remove Multiple Values from Array Using Filter and Loop

I'm new here and need some help with writing a function destroyer() to remove multiple values from an array.
The destroyer() function passes in an array and additional numbers as arguments. The idea is to remove the numbers from the array.
E.g.
destroyer([1, 2, 3, 1, 2, 3], 2, 3)
Output: [1, 1]
destroyer(["tree", "hamburger", 53], "tree", 53)
Output: ["hamburger"]
destroyer([2, 3, 2, 3], 2, 3)
Output: []
Note: the examples only show 2 additional numbers to remove. But the function destroyer() should be able to remove any number of values (i.e. 4, 5, or 6 parameters).
However, my code does not produce the same result. Specifically, using console.log, I see that my filterer function does not loop properly.
1) Can anyone help me debug?
2) Any better way to write this function?
Thank you very much!!!
function destroyer() {
var args = Array.prototype.slice.call(arguments);
var itemToRemove = args.slice(1);
console.log(itemToRemove);
var newArr = args[0];
console.log(newArr);
function filterer(value) {
for (var i = 0; i < itemToRemove.length; i++) {
console.log(i);
console.log(itemToRemove[i]);
if (value != itemToRemove[i]) {
return value;
}
}
}
return newArr.filter(filterer);
}
Your filterer function can be much simpler:
function filterer (value) {
return itemToRemove.indexOf(value) === -1;
}
Using Array.prototype.indexOf() can be inefficient compared to object property lookup in terms of time complexity. I would recommend looping through the additional arguments once and constructing an object with target elements to be destroyed as keys. Then you can check if a given value is a target or not within a filtering callback that you pass to Array.prototype.filter().
function destroyer() {
var arr = arguments.length && arguments[0] || [];
var targets = {};
for (var i = 1; i < arguments.length; i++) {
targets[arguments[i]] = true;
}
return arr.filter(function (x) {
return targets[x] === undefined;
});
}
One downside to this approach is that not all values in JS can be valid properties of an object, since properties must be strings. In this case, you're just using numbers as keys, and those numbers are implicitly converted to strings.
We can pass the arguments an extra parameter to our callback function in our filter() method.
function destroyer(arr) {
return arr.filter(filterer(arguments)); // Pass arguments
}
function filterer(args) {
return function(value) { // Actual filter function
for (var i = 1; i < args.length; i++) {
if (value === args[i]) // Seek
return false; // Destroy
}
return true; // Otherwise keep
};
}
This passes all 5 test cases for freeCodeCamp | Basic Algorithm Scripting | Seek and Destroy.
The following code will remove elements from an array. The elements it removes are defined by any extra parameters. ...remove is an ES6 feature that aggregates extra parameters into a single array.
I will iterate over the ...remove array and delete that element from the main array we are working on.
Here is a JSFiddle: https://jsfiddle.net/zzyopnnp/
...extra_parameters is not supported in most browsers, you may want to use the arguments object.
function removeIndex(array, index) {if(index>-1){array.splice(index, 1);}}
function destroyer(array, ...remove) {
remove.forEach(function(elem, index) {
removeIndex(array, index);
});
};
var arr = ["tree", "hamburger", 53];
destroyer(arr, "tree", 53);
console.log(arr);
A simple function
function filter(arr, arg1, arg2){
var j = arr.length;
while(j){
if (arr.indexOf(arg1) > -1 || arr.indexOf(arg2) > -1){
arr.splice(j - 1, 1);
}
j--
}
}
For multiple arguments
A simple function
function filter(){
var j = -1;
for(var i = 1; i < arguments.length; i++){
j = arguments[0].indexOf(arguments[i]);
if(j > -1){
arguments[0].splice(j, 1);
}
}
return arguments[0];
}
you can call this function with no of args
eg:
filter([1,2,3,4,5,6,7,8,9], 1, 3, 5); //return [2,4,6,7,8,9]
filter([1,2,3,4,5,6,7,8,9], 1); //return [2,3,4,5,6,7,8,9]
There are really good answers here, but you can do it very clean in this way, remember you have an objects option in filter method which you can use in the callback function, in this case i'm using it like : arguments[i] so I can check every value in the arguments array
function destroyer(arr) {
for(var i = 1; i < arguments.length; i++){
arr = arr.filter(isIn, arguments[i]);
}
function isIn(element,index, array){
if (element != this){
return element;
}
}
return arr;
}

Duplicate-free version of array of objects

I implemented a function that creates a duplicate-free version of an array, but it doesn't work for array of objects. I don't understand and I can't find information how to fix it.
My function:
function uniq(array) {
var length = array.length;
if (!length) {
return;
}
var index = 0;
var result = [];
while (index < length) {
var current = array[index];
if (result.indexOf(current) < 0) {
result.push(current);
}
index++;
}
return result;
}
Example:
var my_data = [
{
"first_name":"Bob",
"last_name":"Napkin"
},
{
"first_name":"Billy",
"last_name":"Joe"
},
{
"first_name":"Billy",
"last_name":"Joe",
}
]
uniq([1, 1, 2, 3]) // => [1, 2, 3]
uniq(my_data) // => [ { "first_name":"Bob", "last_name":"Napkin" }, { "first_name":"Billy", "last_name":"Joe" }, { "first_name":"Billy", "last_name":"Joe" } ]
Do you know someone how to creates a duplicate-free version of array of objects?
indexOf() in javascript does not perform a deep comparison of objects. On top of that, any two objects that are created will never be "equal" to each other. If you do:
var a = {};
var b = {};
a == b; //false
a === b; //false
You need to perform a deep comparison against all values (if that's even what you're looking to do, because there could be other equalities you're looking for). I won't go into how to do a deep comparison because, well, Google.
A solution if the objects are not huge, the array doesn't have a huge amount of elements and if the objects don't contain reference loops is to use JSON.stringify to decide if two objects are equal...
function uniq(A) {
var seen = {};
var result = [];
A.forEach(function(x) {
var str = "" + JSON.stringify(x);
if (!seen[str]) {
seen[str] = 1;
result.push(x);
}
});
return result;
}
Since these objects are simply used for data storage (i.e. they don't have methods or prototype extensions and such applied to them), I might suggest serializing and hashing each object in the array and storing the hashes in an object for determination of uniqueness. Now the question is which hashing function to use. There are a number of md5 and SHA-256 implementations available (search StackOverflow for this). My example will just assume the existence of a hash function called hashFunction().
function uniqArrayObjects(array) {
// make sure we have an array
if(Array.isArray(array) === false) {
console.log('Doh! No array passed.');
return null;
}
var length = array.length;
// you can return input array if it has 0 or 1 items in it
// it is already unique
if (length === 0 || length === 1) {
return array;
}
// object for storing hashes
var hashTable = {};
// filter and return the array
return array.filter(function(obj) {
var json = JSON.stringify(obj);
var hash = hashFunction(json);
if (typeof hashTable[hash] === undefined) {
// this item doesn't exist in hash table yet
// add to hash table and return true to add this to filtered result
hashTable[hash] = 1; // value doesn't matter here
return true;
} else {
return false;
}
});
}

Categories

Resources