The best way to remove array element by value - javascript

I have an array like this
arr = ["orange","red","black","white"]
I want to augment the array object defining a deleteElem() method which acts like this:
arr2 = arr.deleteElem("red"); // ["orange","black","white"] (with no hole)
What is the best way to accomplish this task using just the value parameter (no index)?

Here's how it's done:
var arr = ["orange","red","black","white"];
var index = arr.indexOf("red");
if (index >= 0) {
arr.splice( index, 1 );
}
This code will remove 1 occurency of "red" in your Array.

Back when I was new to coding I could hardly tell what splice was doing, and even today it feels less readable.
But readability counts.
I would rather use the filter method like so:
arr = ["orange","red","black","white","red"]
arr = arr.filter(val => val !== "red");
console.log(arr) // ["orange","black","white"]
Note how all occurrences of "red" are removed from the array.
From there, you can easily work with more complex data such as array of objects.
arr = arr.filter(obj => obj.prop !== "red");

There is an underscore method for this, http://underscorejs.org/#without
arr = ["orange","red","black","white"];
arr = _.without(arr, "red");

The trick is to go through the array from end to beginning, so you don't mess up the indices while removing elements.
var deleteMe = function( arr, me ){
var i = arr.length;
while( i-- ) if(arr[i] === me ) arr.splice(i,1);
}
var arr = ["orange","red","black", "orange", "white" , "orange" ];
deleteMe( arr , "orange");
arr is now ["red", "black", "white"]

Array.prototype.deleteElem = function(val) {
var index = this.indexOf(val);
if (index >= 0) this.splice(index, 1);
return this;
};
var arr = ["orange","red","black","white"];
var arr2 = arr.deleteElem("red");

My approach, let's see what others have to say. It supports an "equals" method as well.
// Remove array value
// #param {Object} val
Array.prototype.removeByValue = function (val) {
for (var i = 0; i < this.length; i++) {
var c = this[i];
if (c == val || (val.equals && val.equals(c))) {
this.splice(i, 1);
break;
}
}
};
Read https://stackoverflow.com/a/3010848/356726 for the impact on iterations when using prototype with Array.

Or simply check all items, create a new array with non equal and return it.
var arr = ['orange', 'red', 'black', 'white'];
console.info('before: ' + JSON.stringify(arr));
var deleteElem = function ( val ) {
var new_arr = [];
for ( var i = 0; i < this.length; i++ ) {
if ( this[i] !== val ) {
new_arr.push(this[i]);
}
}
return new_arr;
};
arr = deleteElem('red');
console.info('after: ' + JSON.stringify(arr));
http://jsfiddle.net/jthavn3m/

The best way is to use splice and rebuild new array, because after splice, the length of array does't change.
Check out my answer:
function remove_array_value(array, value) {
var index = array.indexOf(value);
if (index >= 0) {
array.splice(index, 1);
reindex_array(array);
}
}
function reindex_array(array) {
var result = [];
for (var key in array) {
result.push(array[key]);
}
return result;
}
example:
var example_arr = ['apple', 'banana', 'lemon']; // length = 3
remove_array_value(example_arr, 'banana');
banana is deleted and array length = 2

If order the array (changing positions) won't be a problem you can solve like:
var arr = ["orange","red","black","white"];
arr.remove = function ( item ) {
delete arr[item];
arr.sort();
arr.pop();
console.log(arr);
}
arr.remove('red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Here you go:
arr.deleteElem = function ( val ) {
for ( var i = 0; i < this.length; i++ ) {
if ( this[i] === val ) {
this.splice( i, 1 );
return i;
}
}
};
Live demo: http://jsfiddle.net/4vaE2/3/
The deleteElem method returns the index of the removed element.
var idx = arr.deleteElem( 'red' ); // idx is 1

Related

Array.prototype.indexOf() cannot find array inside of multi-dimensional array [duplicate]

Let's say we have the following js array
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
Is there a js builtin function or jQuery one with which you can search the array ar for val?
Thanks
***UPDATE*************
Taking fusion's response I created this prototype
Array.prototype.containsArray = function(val) {
var hash = {};
for(var i=0; i<this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
you could create a hash.
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var hash = {};
for(var i = 0 ; i < ar.length; i += 1) {
hash[ar[i]] = i;
}
var val = [434,677,9,23];
if(hash.hasOwnProperty(val)) {
document.write(hash[val]);
}
You can also use a trick with JSON serializing. It is short and simple, but kind of hacky.
It works, because "[0,1]" === "[0,1]".
Here is the working demo snippet:
Array.prototype.indexOfForArrays = function(search)
{
var searchJson = JSON.stringify(search); // "[3,566,23,79]"
var arrJson = this.map(JSON.stringify); // ["[2,6,89,45]", "[3,566,23,79]", "[434,677,9,23]"]
return arrJson.indexOf(searchJson);
};
var arr = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
document.body.innerText = arr.indexOfForArrays([3,566,23,79]);
function indexOfArray(val, array) {
var hash = {};
for (var i = 0; i < array.length; i++) {
hash[array[i]] = i;
}
return (hash.hasOwnProperty(val)) ? hash[val] : -1;
};
I consider this more useful for than containsArray(). It solves the same problem (using a hash table) but returns the index (rather than only boolean true/false).
Can you try this?
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
var sval = val.join("");
for(var i in ar)
{
var sar = ar[i].join("");
if (sar==sval)
{
alert("found!");
break;
}
}
Why don't you use javascript array functions?
function filterArrayByValues(array, values) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem;
});
});
}
Or if your array is more complicated, and you want compare only one property but as result return whole object:
function filterArrayByValues(array, values, propertyName) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem[propertyName];
});
});
}
More about used functions: filter() and some()
You can use Array.prototype.some(), Array.prototype.every() to check each element of each array.
var ar = [
[2, 6, 89, 45],
[3, 566, 23, 79],
[434, 677, 9, 23]
];
var val = [3, 566, 23, 79];
var bool = ar.some(function(arr) {
return arr.every(function(prop, index) {
return val[index] === prop
})
});
console.log(bool);
I guess there is no such JS functionality available. but you can create one
function arrEquals( one, two )
{
if( one.length != two.length )
{
return false;
}
for( i = 0; i < one.length; i++ )
{
if( one[i] != two[i] )
{
return false;
}
}
return true;
}
The problem with this is that of object/array equality in Javascript. Essentially, the problem is that two arrays are not equal, even if they have the same values. You need to loop through the array and compare the members to your search key (val), but you'll need a way of accurately comparing arrays.
The easiest way round this is to use a library that allows array/object comparison. underscore.js has a very attractive method to do this:
for (var i = 0; i < ar.length; i++) {
if (_.isEqual(ar[i], val)) {
// value is present
}
}
If you don't want to use another library (though I would urge you to -- or at least borrow the message from the Underscore source), you could do this with JSON.stringify...
var valJSON = JSON.stringify(val);
for (var i = 0; i < ar.length; i++) {
if (valJSON === JSON.stringify(ar[i]) {
// value is present
}
}
This will almost certainly be significantly slower, however.
You can use toString convertion to compare elements
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
s = !ar.every(a => (a.toString() != val.toString()));
console.log(s) // true
Use this instead
if (ar.join(".").indexOf(val) > -1) {
return true;
} else {
return false;
}
Use lodash isEqual
const isValIncludedInAr = ar.some(element => isEqual(element, val))
const arrayOne = [2,6,89,45];
const arrayTwo = [3,566,23,79];
const arrayThree = [434,677,9,23];
const data = new Set([arrayOne, arrayTwo, arrayThree]);
// Check array if exist
console.log( data.has(arrayTwo) ); // It will return true.
// If you want to make a set into array it's simple
const arrayData = [...data];
console.log(arrayData); // It will return [[2,6,89,45], [3,566,23,79], [434,677,9,23]]

Remove items from one array if not in the second array

I state that I have tried for a long time before writing this post.
For an InDesign script, I'm working with two array of ListItems. Now I'm trying to remove the items of one array that aren't in the second array, but i'm stuck.
Given that I use the following javascript code (it works great) to remove the equal items between the two arrays :
function check_dupli(arr_A, arr_B) {
for(var i = arr_B.length - 1; i >= 0; i--) {
for(var j = 0; j < arr_A.length; j++) {
if(arr_B[i] === arr_A[j]) {
arr_B.splice(i, 1);
}
}
}
arr_B.sort();
}
arr_A = ["a","b","d","f","g"]
arr_B = ["a","c","f","h"]
check_dupli(arr_A, arr_B) --> arr_B = ["c","h"]
check_dupli(arr_B, arr_A) --> arr_B = ["b","d","g"]
I thought to modify it in order to ignore the items not that are not in both arrays, and to obtain what I want, but something is going wrong because I also get the unwanted data :
function get_dupli(arr_A, arr_B, arr_C) {
for(var e = arr_B.length - 1; e >= 0; e--) {
for(var k = 0; k < arr_A.length; k++) {
if(arr_B[e] === arr_A[k]) {
arr_C.push(arr_B[e]);
}
}
}
arr_C.sort();
}
arr_A = ["a","b","d","f","g"]
arr_B = ["a","g","k"]
arr_C = ["h"]
get_dupli(arr_A, arr_B, arr_C) --> arr_C = ["a","g","h","k"] instead of --> ["a","g","h"]
get_dupli(arr_B, arr_A, arr_C) --> arr_C = ["a","b","d","f","g","h"] instead of --> ["a","g","h"]
Where I'm wrong? There is another way in pure javascript to solve the problem?
Thanks in advance for any help.
You can make use of Array.prototype.filter and Array.prototype.concat to simply it:
arr_A = ["a","b","d","f","g"]
arr_B = ["a","g","k"]
arr_C = ["h"]
function getCommonItems(arrayA, arrayB, result) {
result = result || [];
result = result.concat(arrayA.filter(function(item) {
return arrayB.indexOf(item) >= 0;
}));
return result.sort();
}
alert(getCommonItems(arr_A, arr_B, arr_C).join(", "));
alert(getCommonItems(arr_B, arr_A, arr_C).join(", "));
For the first scenario:
arr_A = ["a","b","d","f","g"]
arr_B = ["a","c","f","h"]
function getDifference(arrayA, arrayB, result) {
return arrayB.filter(function(item) {
return arrayA.indexOf(item) === -1;
}).sort();
}
alert(getDifference(arr_A, arr_B).join(", "));
alert(getDifference(arr_B, arr_A).join(", "));
Do it like this:
//the array which will loose some items
var ar1 = ["a", "b", "c"];
//the array which is the template
var ar2 = ["d", "a", "b"];
var tmpar = [];
for(var i = 0; i < ar1.length; i++){
if(ar2.indexOf(ar1[i]) !== -1){
tmpar.push(ar1[i]);
}
}
ar1 = tmpar;
alert(ar1);
We create a temporary array to store the valid values.
We make sure that the index of the value from the first array is not "-1". If it's "-1" the index is not found and therefore the value is not valid! We store everything which is not "-1" (so we store every valid value).
Array.prototype.contains = function ( object )
{
var i = 0, n = this.length;
for ( i = 0 ; i < n ; i++ )
{
if ( this[i] === object )
{
return true;
}
}
return false;
}
Array.prototype.removeItem = function(value, global) {
var idx;
var n = this.length;
while ( n-- ) {
if ( value instanceof RegExp && value.test ( this[n])
|| this[n] === value ) {
this.splice (n, 1 );
if ( !global ) return this;
}
}
return this;
};
arr_A = ["a","b","d","f","g"];
arr_B = ["a","c","f","h"];
var item
while ( item = arr_A.pop() ) {
arr_B.contains ( item ) && arr_B.removeItem ( item );
}
arr_B;
arr_A = ["a","b","d","f","g"];
arr_B = ["a","c","f","h"];
var newArr = [];
var item
while ( item = arr_B.shift() ) {
arr_A.contains ( item ) && newArr[ newArr.length ] = item ;
}
newArr;// ["a", "f"];
Opsss .... I believed I had given the answer and closed this post ... sorry !!!
Despite all the checks I made, the failure of the mine as your script was caused by a stupid mistake ... the array arr_A passed to the function was a modified copy of the original array.
Thank you all for your concern and help. Sorry again ...

How to find array in array and remove it?

var arr = [["test","1"],["demo","2"]];
// $.inArray() ???
// .splice() ???
// $.each() ???
$("code").html(JSON.stringify(arr));
If I will find matching array by "test" (unique) keyword , I will remove ["test","1"]
So arr after removed will be [["demo","2"]]
How can I do that ?
Playground : http://jsbin.com/ojoxuy/1/edit
This is what filter is for:
newArr = arr.filter(function(item) { return item[0] != "test" })
if you want to modify an existing array instead of creating a new one, just assign it back:
arr = arr.filter(function(item) { return item[0] != "test" })
Modificator methods like splice make code harder to read and debug.
You could do something like this:
function remove(oldArray, itemName) {
var new_array = [];
for(var i = 0, len = oldArray.length; i < len; i++) {
var arr = oldArray[i];
if (arr[0] != itemName) new_array.push(arr);
}
return new_array;
}
And call it like this:
var arr = [["test","1"],["demo","2"]];
var new_arr = remove(arr,'test');
I'm making assumptions here and not doing any real error checking but you get the idea.
Perhaps something like:
for(var i = 0; i < arr.length; i++) {
if(arr[i][0] == "test") {
arr.splice(i, 1);
break;
}
}
var arr = [["test","1"],["demo","2"]];
function checkArrayElements(a, index, arr) {
if(a[0]=="test"){
delete arr[index];
arr.splice(index,index+1);
}
}
arr.forEach(checkArrayElements);
$("code").html(JSON.stringify(arr));
NOTE: This removes any inner array in arr with the 0 element = "test"
Check this one
function rmEl(a,v)
{
for(var i=0;i<a.length;i++)
{
if(a[i][0]==v)
{
a.splice(i,i+1);
i=-1;
}
$("code").html(JSON.stringify(a));
}
return a;
}

String split and count the number of occurrences and also

I have a string
var stringIHave = "Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$";
How to get the count of the number of occurrences of each entry, The occurrence I get, is from a JSON like Java = 8 and etc...
First of all you need to split your srting to array:
var keywordsArr = stringIHave.split( '$$' );
then you need to have an object for example to store counts:
var occur = {};
and then just create simple for loop to count all occurrences:
for( var i = 0; i < keywordsArr.length; i++ ) {
occur[ keywordsArr[ i ] ] = ( occur[ keywordsArr[ i ] ] || 0 ) + 1;
}
now your object occur will have names as keys and count as values.
See jsFiddle demo.
Also as you have at end of your string $$ you maybe will need to remove last item from keywordsArr so just do after split function call:
keywordsArr.pop();
See demo without last element.
So final code will be like:
var stringIHave = "Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$",
keywordsArr = stringIHave.split( '$$' ),
occur = {};
keywordsArr.pop();
for( var i = 0; i < keywordsArr.length; i++ ) {
occur[ keywordsArr[ i ] ] = ( occur[ keywordsArr[ i ] ] || 0 ) + 1;
}
for( var key in occur ) {
document.write( key + ' - ' + occur[key] + '<br/>' );
} ​
I'd suggest the following:
function stringCount(haystack, needle) {
if (!needle || !haystack) {
return false;
}
else {
var words = haystack.split(needle),
count = {};
for (var i = 0, len = words.length; i < len; i++) {
if (count.hasOwnProperty(words[i])) {
count[words[i]] = parseInt(count[words[i]], 10) + 1;
}
else {
count[words[i]] = 1;
}
}
return count;
}
}
console.log(stringCount("Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$", '$$'));
​
JS Fiddle demo.
References:
Object.hasOwnProperty().
parseInt().
String.split().
It's not entirely clear what final objective is. Following creates an object from string that looks like
Object created:
{
"Java": 8,
"jQuery": 4,
"Hibernate": 1,
"Spring": 1,
"Instagram": 1
}
JS:
var str = 'Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$';
var arr = str.split('$$')
var obj = {};
for (i = 0; i < arr.length; i++) {
if (arr[i] != '') {
if (!obj[arr[i]]) {
obj[arr[i]] = 0;
}
obj[arr[i]]++;
}
}
You can loop over the object to get all values or simply look up one value
var jQueryOccurences= obj['jQuery'];
DEMO: http://jsfiddle.net/25hBV/1/
Now a days you can do
const str = "Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$";
var result = str.split("$$").reduce(function(acc, curr) {
curr && (acc[curr] = (acc[curr] + 1) || 1);
return acc
}, {});
console.log(result);
Split the string into an array, and putting the array into an object takes care of duplicates and counts occurences as key/value pairs in the object, see fiddle!
var stringIHave = "Java$$Java$$jQuery$$Java$$jQuery$$Java$$Java$$Java$$Hibernate$$Java$$Java$$Spring$$Instagram$$jQuery$$jQuery$$",
s = stringIHave.split('$$');
obj = {};
for (var i=s.length; i--;) {
obj[s[i]] = (s[i] in obj) ? obj[s[i]]+1 : 1;
}
// obj.Java == 8
FIDDLE
If you want it short and sweet:
// variable declarations
var arParts = stringIHave.match(/\w+/g),
result = {},
i = 0,
item;
// Copy the array to result object
while (item = arParts[i++]) result[item] = (result[item] || 0 ) + 1;
demo

javascript search array of arrays

Let's say we have the following js array
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
Is there a js builtin function or jQuery one with which you can search the array ar for val?
Thanks
***UPDATE*************
Taking fusion's response I created this prototype
Array.prototype.containsArray = function(val) {
var hash = {};
for(var i=0; i<this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
you could create a hash.
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var hash = {};
for(var i = 0 ; i < ar.length; i += 1) {
hash[ar[i]] = i;
}
var val = [434,677,9,23];
if(hash.hasOwnProperty(val)) {
document.write(hash[val]);
}
You can also use a trick with JSON serializing. It is short and simple, but kind of hacky.
It works, because "[0,1]" === "[0,1]".
Here is the working demo snippet:
Array.prototype.indexOfForArrays = function(search)
{
var searchJson = JSON.stringify(search); // "[3,566,23,79]"
var arrJson = this.map(JSON.stringify); // ["[2,6,89,45]", "[3,566,23,79]", "[434,677,9,23]"]
return arrJson.indexOf(searchJson);
};
var arr = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
document.body.innerText = arr.indexOfForArrays([3,566,23,79]);
function indexOfArray(val, array) {
var hash = {};
for (var i = 0; i < array.length; i++) {
hash[array[i]] = i;
}
return (hash.hasOwnProperty(val)) ? hash[val] : -1;
};
I consider this more useful for than containsArray(). It solves the same problem (using a hash table) but returns the index (rather than only boolean true/false).
Can you try this?
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
var sval = val.join("");
for(var i in ar)
{
var sar = ar[i].join("");
if (sar==sval)
{
alert("found!");
break;
}
}
Why don't you use javascript array functions?
function filterArrayByValues(array, values) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem;
});
});
}
Or if your array is more complicated, and you want compare only one property but as result return whole object:
function filterArrayByValues(array, values, propertyName) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem[propertyName];
});
});
}
More about used functions: filter() and some()
You can use Array.prototype.some(), Array.prototype.every() to check each element of each array.
var ar = [
[2, 6, 89, 45],
[3, 566, 23, 79],
[434, 677, 9, 23]
];
var val = [3, 566, 23, 79];
var bool = ar.some(function(arr) {
return arr.every(function(prop, index) {
return val[index] === prop
})
});
console.log(bool);
I guess there is no such JS functionality available. but you can create one
function arrEquals( one, two )
{
if( one.length != two.length )
{
return false;
}
for( i = 0; i < one.length; i++ )
{
if( one[i] != two[i] )
{
return false;
}
}
return true;
}
The problem with this is that of object/array equality in Javascript. Essentially, the problem is that two arrays are not equal, even if they have the same values. You need to loop through the array and compare the members to your search key (val), but you'll need a way of accurately comparing arrays.
The easiest way round this is to use a library that allows array/object comparison. underscore.js has a very attractive method to do this:
for (var i = 0; i < ar.length; i++) {
if (_.isEqual(ar[i], val)) {
// value is present
}
}
If you don't want to use another library (though I would urge you to -- or at least borrow the message from the Underscore source), you could do this with JSON.stringify...
var valJSON = JSON.stringify(val);
for (var i = 0; i < ar.length; i++) {
if (valJSON === JSON.stringify(ar[i]) {
// value is present
}
}
This will almost certainly be significantly slower, however.
You can use toString convertion to compare elements
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
s = !ar.every(a => (a.toString() != val.toString()));
console.log(s) // true
Use this instead
if (ar.join(".").indexOf(val) > -1) {
return true;
} else {
return false;
}
Use lodash isEqual
const isValIncludedInAr = ar.some(element => isEqual(element, val))
const arrayOne = [2,6,89,45];
const arrayTwo = [3,566,23,79];
const arrayThree = [434,677,9,23];
const data = new Set([arrayOne, arrayTwo, arrayThree]);
// Check array if exist
console.log( data.has(arrayTwo) ); // It will return true.
// If you want to make a set into array it's simple
const arrayData = [...data];
console.log(arrayData); // It will return [[2,6,89,45], [3,566,23,79], [434,677,9,23]]

Categories

Resources