I have a 2d array in the format
emi_309 | present | weak | 6
emi_310 | present | strong | 9
emi_319 | present | medium | 8
emi_315 | present | weak | 5
I want to check if a value exists in the first column using a simple function
E.g, check if emi_77 exists in the first column
I came across $.inArray(value, array) but this function is for a 1d array only.
Is there something similar for 2d array
Yes, if you do a combination of $.inArray and $.map:
if ($.inArray(value, $.map(arr, function(v) { return v[0]; })) > -1) {
// ...
}
Can use $.grep to create new array and check it's length
var val='emi_77';
if( $.grep( twoDarray, function(item){ return item[0]===val; }).length){
/* item exists*/
}
$.grep will not affect original array
API Reference: http://api.jquery.com/jQuery.grep/
Here is how I do it simply, without Jquery.
for (var i = 0; i <array.length; i++) {
if(array[i][0] == 'emi_77'){
alert("exists");
}
}
If you wanna take this further, you can use the function below;
function IsIn2D(str,order,array){
for (var i = 0; i <array.length; i++) {
return array[i][order] == str;
}
}
where;
array is the array you want to search
str is the string you want to check if it exists
order is the order of the string in the internal arrays
for example, by appling this to the question's sample 2D array:
emi_309 | present | weak | 6
emi_310 | present | strong | 9
emi_319 | present | medium | 8
emi_315 | present | weak | 5
IsIn2D('emi_77',0,array); /*returns false*/
IsIn2D('emi_315',0,array); /*returns true*/
Check this methods to search from 2D array.
Just check with converting to string and compare.
function isArrayItemExists(array , item) {
for ( var i = 0; i < array.length; i++ ) {
if(JSON.stringify(array[i]) == JSON.stringify(item)){
return true;
}
}
return false;
}
Related
This question already has answers here:
Array.prototype.fill() with object passes reference and not new instance
(7 answers)
Closed 3 years ago.
var arr = new Array(4).fill({});
arr[2].status = true;
console.log(arr[0].status);
why is array fill filling same object in all indexes?
.fill will insert the same exact object (same instance) on each segment of the array.
That's why doing .fill(Math.random) will return an array filled with always the same number.
You can do this to obtain what you want:
new Array(4).fill().map(() => ({}));
To explain what's happening under the hood in your question's code, let's convert this to ES5 code:
var arr = new Array(4); // new Array(4)
var obj = new Object(); // *1: with this object instance
for(i = 0; i < 4; i++) { // .fill( *1 )
arr[i] = obj;
}
As you can see, we are assigning the same object instance (obj) to each cell of the array instance.
This is the same principle of why:
const obj = {};
const a = obj;
const b = obj;
a.foo = true;
Makes a.foo === b.foo resolve to true.
fill repeats the value you pass it. The value in this case is an object reference. Every copy of that reference refers to the same object, so what you're getting is:
+−−−−−−−−−+
arr−−−>| (array) |
+−−−−−−−−−+ +−−−−−−−−−−−−−−+
| 0 |−−+−+−+−>| (object) |
| 1 |−/ / / +−−−−−−−−−−−−−−+
| 2 |−−/ / | status: true |
| 3 |−−−/ +−−−−−−−−−−−−−−+
+−−−−−−−−−+
If you want separate objects, you'll need to create multiple objects. The simplest way is, of course:
var arr = [{}, {}, {}, {}];
Example:
var arr = [{}, {}, {}, {}];
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);
If you want to do it with a variable length:
Since you're using Array.fill, I'm assuming you're using ES2015 (aka "ES6") features (but see below for an ES5-compatible solution without polyfills). You can do that via Array.from with a callback:
const arr = Array.from({length:4}, () => ({}));
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);
That gives you:
+−−−−−−−−−+
arr−−−>| (array) |
+−−−−−−−−−+ +−−−−−−−−−−−−−−+
| 0 |−−−−−−−−>| (object) |
| 1 |−−−−−+ +−−−−−−−−−−−−−−+
| 2 |−−−+ |
| 3 |−+ | | +−−−−−−−−−−−−−−+
+−−−−−−−−−+ | | +−−>| (object) |
| | +−−−−−−−−−−−−−−+
| |
| | +−−−−−−−−−−−−−−+
| +−−−−>| (object) |
| +−−−−−−−−−−−−−−+
| | status: true |
| +−−−−−−−−−−−−−−+
|
| +−−−−−−−−−−−−−−+
+−−−−−−>| (object) |
+−−−−−−−−−−−−−−+
(You can do that with an Array.from polyfill on ES5 if you like, just use function() { return {}; } instead of () => ({}).)
In ES5, if you need a variable length, the simplest thing is probably just a loop:
var arr = [];
for (var i = 0; i < 4; ++i) {
arr[i] = {};
}
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);
You could put that in a helper function, of course.
I have task to receive unique element in order from string as parameter. I do not understand how this function uniqueElements returns ['A','B','C','B'].
var word = "AAAABBBBCCBB";
var uniqueElements = function(word) {
return [].filter.call(word, (function(elem,index) {
return word[index-1] !== elem
}));
}
uniqueElements(word);
//it should return ['A','B','C','B']
I checked and read the following sources:
MDN Mozilla and JS Blog but without success.
The aim of [].filter.call here is to apply the filter method on a string. Naively you would first try to do this:
return word.filter(function(elem,index) {
return word[index-1] !== elem;
});
... which -- if word were an array -- would return the characters in it that satisfy the condition word[index-1] !== elem (which is short for word[index-1] !== word[index]), i.e. each character that is different from the character that precedes it.
But, the filter method only exists on objects that inherit from the Array prototype, which is not the case for strings.
However, filter itself can deal with array-like objects, i.e. objects that have a length and potentially have properties that are numerical. To call filter without a true Array object, you can use call on that function, and then provide the context (i.e. the array-like object) as first argument. The other argument(s) remain the same. So you first need to know where to find the filter method... It is on the Array.prototype, so you would reference it like this:
Array.prototype.filter
But as all arrays have access to this method, it is shorter to just take an empty array, and reference its filter method:
[].filter
Either of the two will work. Now you have to execute the call method on it, and supply the array-like object you want to iterate over:
[].filter.call(words, ...)
The rest is like you would do with a true array: you provide the callback function:
return [].filter.call(word, function(elem,index) {
return word[index-1] !== elem
});
The return value is no longer a string. It is -- like filter always returns -- an array: a real one -- it is created by the filter method.
ES6 way:
In ES6 you can write this in a more readable way, as there now is the Array.from method, which can turn an array-like object to a true array. And then you can just continue with the filter method:
return Array.from(word).filter(function(elem,index) {
return word[index-1] !== elem
});
The spread operator is yet another alternative provided by ES6:
return [...word].filter(function(elem,index) {
return word[index-1] !== elem
});
var uniqueElements = function(word) {
return [].filter.call(word, (function(elem,index) {
return word[index-1] !== elem
}));
}
is equivalent to
var uniqueElements = function(word) {
return word.split("").filter(function(elem,index) {
return word[index-1] !== elem
});
}
which should already be clearer: it turns word into an array of char then filters every char that is different from the previous one. This explains why "B" is present twice in the result.
To get unique elements, you can do
var uniqueElements = function(word) {
var res = []
word.split("").forEach(function(val){
if (res.indexOf(val)===-1) res.push(val);
});
return res
}
It's performing an explicit call() on the filter method on the array object so they can pass in a string. They're just using [] instead of Array because it's shorter syntax or someone was trying to be clever when they wrote it.
Normally, the filter() method would affect the array's own contents. However, by call()-ing it, you can change the context by passing in another array, or in this case, a string (which is treated as an array of characters). It then runs the supplied function for each element, keeping the element if the return value of the function is true.
If you don't understand what a code do, you can log actions ! IE
var word = "AAAABBBBCCBB";
function uniqueElements(word){
return [].filter.call(word,(
function(elem,index) {
console.log("Index : "+index+" | Elem : " +elem+" | CompareTo "+word[index-1]);
return word[index-1] !== elem;
}
));
}
uniqueElements(word);
You will get the following input :
Index : 0 | Elem : A | CompareTo undefined
Index : 1 | Elem : A | CompareTo A
Index : 2 | Elem : A | CompareTo A
Index : 3 | Elem : A | CompareTo A
Index : 4 | Elem : B | CompareTo A
Index : 5 | Elem : B | CompareTo B
Index : 6 | Elem : B | CompareTo B
Index : 7 | Elem : B | CompareTo B
Index : 8 | Elem : C | CompareTo B
Index : 9 | Elem : C | CompareTo C
Index : 10 | Elem : B | CompareTo C
Index : 11 | Elem : B | CompareTo B
Using this, you can check that every element who aren't equal than the one before are send to your array.
Few answers/comments already pointed out how [].filter.call() work.
If you want to get a String instead of an array, simply add .join("") IE
var word = "AAAABBBBCCBB";
function uniqueElements(word){
return [].filter.call(word,(
function(elem,index) {
console.log("Index : "+index+" | Elem : " +elem+" | CompareTo "+word[index-1]);
return word[index-1] !== elem;
}
)).join("");
}
uniqueElements(word);
I've split the code into smaller parts with inline comments for better understanding.
var word = "AAAABBBBCCBB";
var uniqueElements = function(word){
// this is the filter function
// this function will get each element of the string with its index
var filterFunction = function(elem, index) {
// the elements who pass the following condition are kept
// the condition -
// if the character at the previous index (index-1) is not equal to the
// current element, then keep the element
return word[index-1] !== elem;
}
// the below is equivalent to Array.prototype.filter.call(context, filterFunction)
return [].filter.call(word, filterFunction);
}
console.log(uniqueElements(word));
I would do this O(n) time by utilizing Array.prototype.reduce() as follows;
var str = "AAAABBBBCCBB",
uniques = Array.prototype.reduce.call(str, (p,c,i) => i-1 ? p[p.length-1] !== c ? (p.push(c),p)
: p
: [c]);
console.log(uniques);
var word = "AAAABBBBCCBB";
var unique = word.split('').filter(function(item, i, ar) {
return ar.indexOf(item) === i;
}).join('');
I've noticed some strange behavior in the array filters on node.js.
There is a simple array and a loop:
var array = [
{
name:"bob",
planet:"earth"
},
{
name:"mike",
planet:"mars"
},
{
name:"vlad",
planet:"jupiter"
}];
var filtered = array.filter(function(x){
return x.name !== "mike";
});
console.log(array); //lets print how normal array looks like
console.log("---");
console.log(filtered); //lets print how filtered one looks like
for(var i = 0; i < filtered.length; i++)
{
delete filtered[i].planet; //remove planet
filtered[i].name = filtered[i].name + "[NEW]"; //add NEW to the name
}
console.log("After replacement:");
console.log(array);//lets print how normal array looks like now
console.log("-----------");
console.log(filtered);//lets print how filtered array looks like now
In theory, array array should not be changed, since I did not manipulate it in any way. Hovewer, this is what I get in console:
[ { name: 'bob', planet: 'earth' },
{ name: 'mike', planet: 'mars' },
{ name: 'vlad', planet: 'jupiter' } ] //this array is normal
---
[ { name: 'bob', planet: 'earth' },
{ name: 'vlad', planet: 'jupiter' } ] //this is good behavior, since I don't need "mike"
After replacement:
[ { name: 'bob[NEW]' },
{ name: 'mike', planet: 'mars' },
{ name: 'vlad[NEW]' } ] //this should not be changed in any way
-----------
[ { name: 'bob[NEW]' }, { name: 'vlad[NEW]' } ] //this is correct
Why does this happen? I need array to stay the same as in the beginning.
Thanks.
Your code here:
for(var i = 0; i < filtered.length; i++)
{
delete filtered[i].planet; //remove planet
filtered[i].name = filtered[i].name + "[NEW]"; //add NEW to the name
}
...isn't changing either array. It's changing the state of the objects that both arrays refer to.
Simpler example:
var a = [{answer:null}];
var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis
a[0].answer = 42;
console.log(b[0].answer); // 42
This line:
a[0].answer = 42;
doesn't change a or b, it changes the state of what a[0] refers to, which b[0] also refers to.
Let's throw some ASCII-art Unicode-art at it:
After this line:
var a = [{answer:null}];
this is what we have in memory (ignoring some irrelevant details);
+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| Ref11542 |−−−−>| array |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| 0: Ref88464 |−−−−>| object |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| answer: null |
+−−−−−−−−−−−−−−+
a refers to an array object, which has a 0 property, which refers to the object with the answer property. I'm using "Ref11542" and "Ref88494" to represent the object references that a and a[0] contain, but of course we never actually see the value of those references; they're private to the JavaScript engine.
Then we do this:
var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis
Now we have:
+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| Ref11542 |−−−−>| array |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| 0: Ref88464 |−−+
+−−−−−−−−−−−−−−+ |
|
| +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−>| object |
| variable "b" | | +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | | answer: null |
| Ref66854 |−−−−>| array | | +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ |
| 0: Ref88464 |−−+
+−−−−−−−−−−−−−−+
Note that both arrays contain the same object reference (shown here as "Ref88464"); they point to the same object.
Now we do this:
a[0].answer = 42;
All that does is change the state of the object; it has no effect on a or b or the arrays they refer to:
+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| Ref11542 |−−−−>| array |
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+
| 0: Ref88464 |−−+
+−−−−−−−−−−−−−−+ |
|
| +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−>| object |
| variable "b" | | +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | | answer: 42 |
| Ref66854 |−−−−>| array | | +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | ^
| 0: Ref88464 |−−+ +−−−−−−− only change is here
+−−−−−−−−−−−−−−+
So naturally
console.log(b[0].answer);
...outputs 42.
In a comment you've asked:
But then how do I set the state of filtered object and not the main one?
Remember, the objects are the same in both arrays. You haven't copied the objects, you've just created a new array that only has some of them in it.
If you want to be able to change those objects' properties without affecting the objects in the first array, you need to make copies of the objects.
If the objects contain only simple primitive values, that's easy; the general case is quite hard. :-)
In your case, though, since your objets just have name and planet properties, and the very next thing you do is remove the planet property and change the name, we can easily create objects as we go; see comments:
var array = [
{
name:"bob",
planet:"earth"
},
{
name:"mike",
planet:"mars"
},
{
name:"vlad",
planet:"jupiter"
}];
var filtered = array.filter(function(x){
return x.name !== "mike";
}).map(function(x) {
// Create a *new* object, setting its `name` to the `name`
// of the original object plus [NEW], and ignoring its
// `planet` property entirely
return {name: x.name + "[NEW]"};
});
console.log(array);
console.log("---");
console.log(filtered);
Alternately, you might want to make just one pass through the array:
var filtered = [];
array.forEach(function(x){
if (x.name !== "mike") {
filtered.push({name: x.name + "[NEW]"});
}
});
I've been playing this for a while. Why is val_a changed when I run the function to sort val b? How can I get around this? When I run the function separately they work, but when I run them together something goes wrong somewhere.
var GLOBALS = {"items":[]};
var val_a;
var val_b;
GLOBALS.items=[
{"thing":"one","val_a":0.5,"val_b":0.2},
{"thing":"two","val_a":0.2,"val_b":0.3},
{"thing":"three","val_a":0.3,"val_b":0.1}];
val_a = GLOBALS.items.sort(function (a, b) {
a=parseFloat(a.val_a);
b=parseFloat(b.val_a);
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
});
val_b = GLOBALS.items.sort(function (a, b) {
a=parseFloat(a.val_b);
b=parseFloat(b.val_b);
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
});
console.log("val_a",val_a);
console.log("val_b",val_b);
The reason you're seeing what you're seeing is that val_a and val_b just contain references to the same array, which is also referenced from GLOBALS.items. sort changes the state of the array that all three of those variables are pointing to.
Variables contain values, not objects. When dealing with objects (including arrays), the value in the variable is a reference to the object, which actually exists elsewhere in memory. Think of that reference as a number telling the JavaScript engine where the object is elsewhere in memory. (More below.)
If you want three separate arrays (the original items, then a copy sorted by val_a, and another sorted by val_b), you want to make a shallow copy of the array before sorting it, which you can do with slice:
val_a = GLOBALS.items.slice().sort(...);
About the array being elsewhere in memory, here's a simpler example:
var a = [42]; // A variable with a reference to an array, which is
// elsewhere in memory
That gives us this in memory:
+---------+
a<REF5512>--------->| (array) |
+---------+
| 0: 42 |
+---------+
(That REF5512 is just completely made up to make the point that a reference is a value. We never see the raw reference values.)
Then if we do:
var b = a; // A copy of that same reference
That gives us this in memory:
a<REF5512>---+
| +---------+
+----->| (array) |
| +---------+
b<REF5512>---+ | 0: 42 |
+---------+
If we change the state of the array (for instance, by sorting it), naturally that change is visible from either variable, as they're both referring to the same array:
b[0] = 67;
gives us
a<REF5512>---+
| +---------+
+----->| (array) |
| +---------+
b<REF5512>---+ | 0: 67 | State of the array changed
+---------+
slice creates a new array with a copy of the values in the old array (just the values; the objects in your array aren't copied). So for instance:
b = a.slice();
Gives us:
+---------+
a<REF5512>--------->| (array) |
+---------+
| 0: 67 |
+---------+
+---------+
b<REF7341>--------->| (array) |
+---------+
| 0: 67 |
+---------+
Note how the reference in b is no longer the same as in a.
Side note: Your sort callbacks can be much simpler:
val_a = GLOBALS.items.sort(function (a, b) {
return parseFloat(a.val_a) - parseFloat(b.val_a);
});
The sort callback just has to return a value less than zero (it doesn't have to be specifically -1), greater than zero (it doesn't have to be specifically 1), or equal to zero.
How do I keep a function working with local variables from changing the value of a global? It's like I've passed the value by reference without meaning to do so.
https://github.com/upstageleft/Weird-javascript-problem
Global variable keeps changing when source data (value of an element from a matrix array in a closure) is copied to a local variable and then the local variable value is modified.
Cannot wrap my head around what is going on, but problem renders consistently in FF, Safari and Chrome.
Link includes code and dynamic display of variable values with button to repeat. Should be enough, but you can always view source to verify.
EXAMPLE DATA:
In the lists below, the first item reflects the value of a global variable populated by a value copied from a matrix array in a closure by means of a helper function.
The second list shows that the global value has changed when it should not have. The value of the specified cell of the matrix has been copied to a new variable, and that variable has been manipulated, but the result of that manipulation is somehow copied back to both the global variable and the matrix variable!
globVal initial value: 1,1 ←(should be constant)
globVar's scope: [object Window]
myObj: { oSrc: "1,1", oX: 2 }
Before:
globVal[0] (global): 1
Operation: newVal = myVal[0] * myObj.oX
myVal[0] (local): 1
newVal (local): 2
map.see(1,1) (closure): 1,1
After:
globVal[0] (global): 2
Operation: myVal[0] = newVal
myVal[0] (local): 2
newVal (local): 2
map.see(1,1) (closure): 2,1
Here is the code performing the operations, along with a helper function to pull values from the matrix and the object containing the data value to be applied in the operations.
CODE BLOCK A
1 | function doStuff(){
2 | var myVal = mxGet( myObj.oSrc );
3 | var newVal = myVal[0] * myObj.oX;
4 | myVal[0] = newVal; // weirdness happens here!
5 | }
6 |
7 | function mxGet( xy ){
8 | var x_y = xy.split(',');
9 | return map.see( x_y[0], x_y[1] );
10 | }
11 |
12 | myObj = {
13 | oSrc: '1,1',
14 | oX: 2
15 | }
Here are the onload function which initializes the global and the closure which stores the matrix.
CODE BLOCK B
1 | function init(){
2 | globVal = mxGet('1,1'); // global declared here
3 | that = this;
4 | doStuff();
5 | }
6 |
7 | map = (function(){
8 | myHiddenMatrix = [ [ [0,0], [0,1], [0,2] ],
9 | [ [1,0], [1,1], [1,2] ],
10 | [ [2,0], [2,1], [2,2] ] ];
11 | return {
12 | pin: function( x, y, val ){ myHiddenMatrix[ x ][ y ] = val; },
13 | see: function( x, y ){ return myHiddenMatrix[ x ][ y ]; }
14 | }
15 | })();
This is how javascript (and a lot of modern languages) works. Objects are (essentially) passed by reference whether you like it or not.
See more here:
Does Javascript pass by reference?
When you're setting your global, you're setting it to the reference of the object returned by mxGet('1,1') in this line:
globVal = mxGet('1,1');
If you want that to be a new object instead, then you actually have to set globVal to a newly created object, like a new Array such as:
var x = mxGet('1,1');
globVal = [ x[0], x[1] ];
This will make globVal stay the same. It's a subtle, but important, difference.