This question already has answers here:
Looping through array and removing items, without breaking for loop
(17 answers)
Closed 2 years ago.
So i'm trying to write a function that deletes all the strings from array.
It works, but deletes only half of them, why?
let list = [1,2,'a','b', 'c', 'd', 'e'];
function filter_list(l) {
for (let i = 0; i < l.length; i++) {
if(typeof l[i] === 'string') {
l.splice(l.indexOf(l[i]), 1);
}
}
console.log(l)
}
filter_list(list)
Use Array.prototype.filter() to return a filtered subset Array, and typeof to check the operand type:
const list = [1,2,'a','b', 'c', 'd', 'e'];
const nums = list.filter(x => typeof x !== "string");
console.log(nums)
const list = [1,2,'a','b', 'c', 'd', 'e'];
const nums = list.filter(i => typeof i !== "string");
console.log(nums)
This checks each element and excludes those of type string.
How can I iterate every odd or even properties from the object, when property keys are only strings, not numbers?
var object = {
odd1: 'a',
even2: 'b',
odd3: 'c',
even4: 'd'
};
//Edit: The keys are not duplicated.
var object = {
odd1: 'a',
even2: 'b',
odd3: 'c',
even4: 'd'
};
var od = []; var ev = [];
var len = Object.keys(object).length;
var keys = Object.keys( object );
for (var i = 0; i < len; i++) {
if(i%2 === 0){
ev.push(keys[i]);
}
else {
od.push(keys[i]);
}
}
alert("odd values are: "+od+" and even values are: "+ev );
So for first, you can't have two properties with the same name. There is no order for the object properties. The latest one will override the previous value.
To iterate over the properties you can use Object#keys, which will return own properties of the object. And you can see that there are only 2 properties in the object.
"use strict"
var object = {
odd: 'a',
even: 'b',
odd: 'c',
even: 'd'
};
Object.keys(object).forEach(prop => console.log(`${prop} - ${object[prop]}`));
iterate every odd or even properties from the object, when property
keys are only strings, not numbers?
This is essentially iterating over the entire object. For that you can use for ..in
var object = {
'1': 'a',
'2': 'b',
'3': 'c',
'4': 'd'
};
for (var keys in object) {
console.log(object[keys])
}
I have an array
sourceArray = [{'type':'A'}, {'type':'B'}, {'type':'C'}, {'type':'D'}];
arrayB = ['B', 'C'];
I want to filter array sourceArray from values which arrayB contains.
We can do this by iterating arrayB, but just want some good way to do this.
filteredArray = [];
for(x in arrayB)
{
filteredArray.concat( sourceArray.filter(function(e1){ return e1.type == arrayB[x])} );
}
can be have any way to do this more gracefully.
Just .filter it:
sourceArray = [{'type':'A'}, {'type':'B'}, {'type':'C'}, {'type':'D'}];
arrayB = ['B', 'C'];
result = sourceArray.filter(function(item) {
return arrayB.indexOf(item.type) >= 0;
});
document.write("<pre>" + JSON.stringify(result,0,3));
[].filter(func) iterates an array and collects elements for which func returns true. In our function, we check whether arrayB contains item.type and return true if it does (see indexOf).
ES6 solution, for those who already use it:
sourceArray = [{'type':'A'}, {'type':'B'}, {'type':'C'}, {'type':'D'}];
arrayB = ['B', 'C'];
setB = new Set(arrayB)
result = sourceArray.filter(item => setB.has(item.type))
There's the solution of filtering and using indexOf, but it contains a hidden iteration which is costly if your arrayB array contains more than just a few elements.
In the general case, the efficient solution is to build a hash map of the elements so that the filtering operation is faster. This can be done like this:
var filteredArray = sourceArray.filter(
function(v){ return this[v.type] }.bind(arrayB.reduce(
function(s,v){ s[v]=1; return s }, Object.create(null)
))
)
In this code arrayB.reduce(function(s,v){ s[v]=1; return s }, {})) is an object whose keys are the valid types : {B: 1, C: 1}. JavaScript engines are very fast at repetitively retrieving the properties of such an object.
var sourceArray = [{
'type': 'A'
}, {
'type': 'B'
}, {
'type': 'C'
}, {
'type': 'D'
}];
var arrayB = ['B', 'C'];
var desiredArr = sourceArray.filter(function (val) {
for (var i = 0; i <= arrayB.length; ++i) {
if (val.type == arrayB[i]){
return val;
}
}
});
alert(JSON.stringify(desiredArr));
If i have a multidimensional array like: [[a,b],[a,c],[b,a],[b,c],[c,a],[c,b]] how can i go through and remove repeats where [a,b] is the same as [b,a].
also, the array is actually massive, in the tens of thousands. A for loop would have to be done backwards because the array length will shrink on every iteration. Im not even sure that an each loop would work for this. I really am at a loss for just a concept on how to begin.
Also, i tried searching for this for about an hour, and i don't even know how to phrase it.
I think I'm going to try a different approach to this problem. I also think it'll be quicker than some of the solutions proposed (though we'd need of course to test it and benchmark it).
First off, why don't we take advantage of the hash oriented nature of javascript arrays and objects? We could create an object containing the relations (in order to create a kind of a map) and store in a new array those relationships that hasn't been stored yet. With this approach there's no problem about objects either, we just request for an identifier or hash or whatever for every object. This identifier must make the relationship between them possible.
UPDATE
The script now controls the possibility of repeated elements f.e [[a,b],[a,b]]
The script now controls the possibility of elements with the same object repeated f.e [[a,a],[a,a][a,a]] would return [a,a]
The code:
var temp = {},
massive_arr = [['a','b'],['a','c'],['a','d'], ['b','a'],['b','c'],['b','d'],['c','a'],['c','b'],['c','d']],
final_arr = [],
i = 0,
id1,
id2;
for( ; i < massive_arr.length; i++ ) {
id0 = objectIdentifier(massive_arr[i][0]);// Identifier of first object
id1 = objectIdentifier(massive_arr[i][1]);// Identifier of second object
if(!temp[id0]) {// If the attribute doesn't exist in the temporary object, we create it.
temp[id0] = {};
temp[id0][id1] = 1;
} else {// if it exists, we add the new key.
temp[id0][id1] = 1;
}
if( id0 === id1 && !temp[id0][id1+"_bis"] ) {// Especial case [a,a]
temp[id0][id1+"_bis"] = 1;
final_arr.push(massive_arr[i]);
continue;// Jump to next iteration
}
if (!temp[id1]) {// Store element and mark it as stored.
temp[id1] = {};
temp[id1][id0] = 1;
final_arr.push(massive_arr[i]);
continue;// Jump to next iteration
}
if (!temp[id1][id0]) {// Store element and mark it as stored.
temp[id1][id0] = 1;
final_arr.push(massive_arr[i]);
}
}
console.log(final_arr);
function objectIdentifier(obj) {
return obj;// You must return a valid identifier for the object. For instance, obj.id or obj.hashMap... whatever that identifies it unequivocally.
}
You can test it here
SECOND UPDATE
Though this is not what was requested in the first place, I've changed the method a bit to adapt it to elements of n length (n can vary if desired).
This method is slower due to the fact that relies on sort to generate a valid key for the map. Even so, I think it's fast enough.
var temp = {},
massive_arr = [
['a', 'a', 'a'], //0
['a', 'a', 'b'], //1
['a', 'b', 'a'],
['a', 'a', 'b'],
['a', 'c', 'b'], //2
['a', 'c', 'd'], //3
['b', 'b', 'c'], //4
['b', 'b', 'b'], //5
['b', 'b', 'b'],
['b', 'c', 'b'],
['b', 'c', 'd'], //6
['b', 'd', 'a'], //7
['c', 'd', 'b'],
['c', 'a', 'c'], //8
['c', 'c', 'a'],
['c', 'd', 'a', 'j'], // 9
['c', 'd', 'a', 'j', 'k'], // 10
['c', 'd', 'a', 'o'], //11
['c', 'd', 'a']
],
final_arr = [],
i = 0,
j,
ord,
key;
for (; i < massive_arr.length; i++) {
ord = [];
for (j = 0; j < massive_arr[i].length; j++) {
ord.push(objectIdentifier(massive_arr[i][j]));
}
ord.sort();
key = ord.toString();
if (!temp[key]) {
temp[key] = 1;
final_arr.push(massive_arr[i]);
}
}
console.log(final_arr);
function objectIdentifier(obj) {
return obj;
}
It can be tested here
Based on my understanding that you want to remove from the parent array any children arrays which hold the same set of objects without regard for order, this should do it is some code:
function getId(obj) { // apparently these objects have identifiers
return obj._id; // I'm testing with MongoDB documents
}
function arraysEqual(a, b) {
if (a === b) { return true; }
if (a == null || b == null) { return false; }
if (a.length != b.length) { return false; }
aIds = []; bIds = [];
for (var i = 0; i < a.length; i++) {
aIds.push(getId(a[i])); bIds.push(getId(b[i]));
}
aIds.sort(); bIds.sort();
for ( var i = 0; i < aIds.length; i++ ) {
if(aIds[i] !== bIds[i]) { return false; }
}
return true;
}
function removeRepeats(list) {
var i, j;
for (i=0; i < list.length; i++) {
for (j=i+1; j < list.length; j++) {
if (arraysEqual(list[i], list[j])) {
list.splice(j,1);
}
}
}
}
The removeRepeats function goes through each element and compares it with every element that comes after it. The arraysEqual function simply returns true if the arrays are equal. The isEquivalent function should test object equivalence. As noted on that webpage, there are libraries that test object equivalence. If you are okay with adding those libraries, you can replace the isEquivalent function with _.isEqual.
***
* Turns out the OP has objects in his list, so this approach won't
* work in that case. I'll leave this for future reference.
***
var foo = [['a','b'],['a','c'],['b','a'],['b','c'],['c','a'],['c','b']];
function removeRepeats(list) {
var i;
var b = [];
var _c = [];
for (i = 0; i < list.length; i++) {
var a = list[i].sort();
var stra = a.join("-");
if(_c.indexOf(stra) === -1) {
b.push(a);
_c.push(stra);
}
}
return b;
}
console.log(removeRepeats(foo));
It's not the most pretty code I've ever produced, but it should be enough to get you started I guess. What I'm doing is creating two new arrays, b and _c. b will be the array without the repeats. _c is a helper array which contains all the unique pairs already processed as a string, so I can do easy string comparisons while looping through list.
I have defined an array like so :
var myArray = {myNewArray: ['string1' , 'string2' , 'string3']};
I want to iterate over the array and delete an element that matches a particular string value. Is there a clean way in jQuery/javascript to achieve this ?
Or do I need to iterate over each element, check its value and if its value matches the string im comparing, get its id and then use that id to delete from the array ?
Here's a JSFiddle showing your solution
var strings = ['a', 'b', 'c', 'd'];
document.write('initial data: ' + strings);
var index = 0;
var badData = 'c';
for(index = 0; index < strings.length; index++)
{
if(strings[index] == badData)
{
strings.splice(index, 1);
}
}
document.write('<br>final data: '+ strings);
JavaScript arrays have an indexOf method that can be used to find an element, then splice can be used to remove it. For example:
var myNewArray = ['A', 'B', 'C'];
var toBeRemoved = 'B';
var indexOfItemToRemove = myNewArray.indexOf(toBeRemoved);
if (indexOfItemToRemove >= 0) {
myNewArray.splice(indexOfItemToRemove, 1);
}
After that code executes, myNewArray is ['A', 'C'].
You can use Array.filter.
filteredArray = myArray.myNewArray.filter(function(el){
return el === "string";
});
You can check compatibility at Kangax's compat tables.
You could filter the array using $.grep
var myArray = {myNewArray: ['string1' , 'string2' , 'string3']};
myArray = { myNewArray: $.grep(myArray.myNewArray,function(val){
return val !== "string1";
})};
//console.log(myArray);
my newARR = oldArr.splice( $.inArray( removeItem , oldArr ) , 'deleteThisString');