What would be the best approach to check if all the elements of a given array are contained by another array? For example:
match(['countryaarea', 'countrybarea'], ['countrya', 'countryb']) // true
I have tried indexOf() and includes(), but it does not work.
You can use every and some methods.
const arr = ['countryaarea', 'countrybarea'];
function match(array, searchArray) {
if (array.length !== searchArray.length) {
return false;
}
return array.every(el => searchArray.some(sEl => el.includes(sEl)));
}
console.log(match(arr, ['countrya', 'countryb'])); // returns true
console.log(match(arr, ['countrya'])) // returns false
console.log(match(arr, ['abcd'])) // returns false
console.log(match(arr, [])) // returns false
You would also want to check for null values.
... best approach...
The 'best approach' is robust code that handles edge cases. But the OP is insufficient to know what the edge cases are. That's addressed below but first, the code.
function isSubset ( subset, reference ) {
if ( !Array.isArray( subset ) || !Array.isArray( reference )) return false;
return subset.every( element => reference.includes( element ));
}
The 'best approach' for coding:
generally almost never involves for loops. Less readable and more error prone than Iterator functions. And as seen in the other answers, for loops put artificial constraints on the problem.
Code composition using functions is in keeping with Javascript language design, functional programming paradigm, OO principles, and clean code in general.
The 'best approach' depends on desired functionality:
Must the arrays be the same length? All answers (as of this writing) assumes that.
Must the test-array be shorter and/or equal length of the reference array?
Can either or both arrays have duplicate items?
Is this throw-away code ?
Is this destined for a library or at least production code?
What if there are mixed types in either or both arrays?
If this is simply "git er done", isolated use then verbose-but-understood code is OK and non-robust parameter checking is OK.
My assumptions
Return false for failed parameter checks, don't just blow up.
Both things must be arrays.
No constraints on array length.
Duplicate elements in either array do not need item-for-item duplication in the other.
An empty array is a subset of any other array including another empty array.
String compare is case sensitive.
I did not want to get wrapped around the axle with using "truthiness" for parameter validation so I left that sleeping demon alone.
var arraysMatch = function (arr1, arr2) {
// Check if the arrays are the same length
if (arr1.length !== arr2.length) return false;
// Check if all items exist and are in the same order
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
// Otherwise, return true
return true;
};
Related
So here is my solution:
let data = [11, null, NaN, 'Hello', 24]
let check = 0;
for (item in data) {
if (isNaN(item) == false) {
check +=1
};
};
console.log(check);
How ever the answer comes five, even though it is 2. I believe isNaN() function gives true or false, so why is it not working?
The in in item in data checks the properties of an object. In an array, the keys are numbers, you have five entries, so you get five times not isNan().
You want to iterate the array, so it should be let item of data
for...in loops over the properties of an object. To loop over an array's elements, use for...of or Array#forEach.
For this specific case, Array#reduce is particularly appropriate.
let data = [11, null, NaN, 'Hello', 24];
let res = data.reduce((a, b) => a + !isNaN(b), 0);
console.log(res);
Your code returns 5 because for...in iterates over the array keys. And the array keys of data are the numbers between and including 0 and 4. Five in total, all of them are numbers.
There are multiple ways to write the code.
Using for...in, use item as an index in data (because this is what it is):
const data = [11, null, NaN, 'Hello', 24]
let check = 0;
for (item in data) {
if (isNaN(data[item]) == false) {
check += 1;
}
}
console.log(check);
Using for...of, item is a value from data and the rest of your code works fine:
const data = [11, null, NaN, 'Hello', 24]
let check = 0;
for (item of data) {
if (isNaN(item) == false) {
check += 1;
}
}
console.log(check);
Using Array.forEach() you get both the index and the value as arguments of the callback function. The value is the first argument, the index is not needed (but it is available as the second argument):
const data = [11, null, NaN, 'Hello', 24]
let check = 0;
data.forEach((item) => {
if (isNaN(item) == false) {
check ++;
}
});
console.log(check);
The callback function used by Array.forEach() changes a variable that is neither received as argument, nor a local variable of the callback function. The code is somewhat confusing this way and it is not properly encapsulated. While this is fine because there is not better option, here it can be done better using Array.reduce(). Array.reduce() seems to be closer to what the program wants to achieve than Array.forEach() (that is just a cleaner way to write the two for loops attended before).
const data = [11, null, NaN, 'Hello', 24]
let check = data.reduce(
(acc, item) => {
if (isNaN(item) == false) {
acc ++;
}
return acc;
},
0
);
console.log(check);
However, Array.reduce() is still a wrong fit. The purpose of the code is to count the numbers from the data array. A more natural way is to not count them but to extract the numbers into a new array using Array.filter(). The array itself tells us how many items it contains by accessing its .length property. There is no need for ifs:
const data = [11, null, NaN, 'Hello', 24]
const check = data.filter((item) => !isNaN(item)).length;
console.log(check);
Other remarks
Do not put semicolons (;) after the close brace } of a code block. The semicolon is a statement separator and a code block can be used wherever a statement can be used. All in all the following piece of code
if (true) {
};
... contains two statements. One is if (true) with an empty code block on the if branch, the other is an empty statement that follows the code block until the semicolon.
It does not have any undesired effect here but it can be the source of hidden bugs difficult to find.
The semicolon is required only after some JavaScript statements. For all the others, a new line works the same as a semicolon. More than that, the JavaScript interpreter is able to insert some missing semicolons automagically.
Attention! I do not say to never use semicolons. Use them where they must be used but be aware that a missing semicolon is either inserted by the interpreter or flagged as a syntax error (and the program does not start) while an extra semicolon in the wrong place can make your program behave in an unexpected way.
Do not use == and !=. They do loose comparisons (f.e. 2 == '2') and sometimes they have surprising results. Always use the strict equality operator (===) and the strict inequality operator (!==). They first check the types of the two operands and do not do confusing conversions to check the values.
x += 1 is usually written x ++. Be aware that, in some contexts, x ++ is has different side effects than ++ x.
There is nothing wrong with += 1, just nobody uses it.
Sometimes, using the logical NOT operator (!) the code becomes more clear. It is abused by many developers that produce "clever" but unclear code but using it here is better than comparing against false.
To me, if (! isNaN(item)) seems easier to understand than if (isNaN(item) === false). It can almost be read: "if item is not NaN" vs. "if item is not NaN is false".
It does not make any difference to the interpreter though. Write the code to be easy to read and understand. The computer does not care.
I have an array of objects:
var allButtons = [
buttonA,
buttonВ,
buttonС,
"->"
];
This objects can have the property 'hidden' which can be true or false.
I need to discover (in an optimal way), whether any of this 'buttons' have hidden === false (in other words, are visible).
Now i use this primitive approach:
someOfButtonsIsVisible = false;
Ext.each(allButtons, function (item){
if(item.hidden === false) {
someOfButtonsIsVisible = true;
}
});
But in this case i have to go through all objects and check their 'hidden' property.
Is there a better way to know whether any of objects in array have hidden === false?
Use array.prototype.some:
var someOfButtonsIsVisible = allButtons.some(button => button.hidden === false);
It can also be done with array.prototype.every:
var someOfButtonsIsVisible = !allButtons.every(button => button.hidden === true);
But in your case, array.prototype.some make more sense
Use Array.prototype.find().
The find() method returns the value of the first element in the array that satisfies the provided testing function.
Find will traverse your array, and stop once it found the value wanted. You can then test the return value if it's different from undefined.
Edit: If your goal is to identitfy if at least one (or some) value are false, then array.some()is better. If you goal is to retrieve the value which match hidden === false then array.find() is better.
This is a classic case of sequential search.
No matter what you use the time complexity will vary between O(1)(best case) to O(n)(worst case).
Now if you can sort the array so that the visible buttons are added to the top then the search logic will always have a time complexity of O(1)
Note: break the loop after satisfying the condition.
often time I missed one or two checking thus it break the entire app. I really feel this is a pain in writing in js because one simple mistake can ruin entire app.
Take this code
{this.state.floor && this.state.floor[this.state.selectedTab].units.length === 0 && <div>render something</div>}
it will have error if units is undefined. How to I check? the first check this.state.floor doesn't seem to work. Should I check if this.state.floor.length > 1?
If the return of data has nested or multiple nested properties, my jsx will be so complicated sometime.
you can do it with lodash get function like this :
const r = {a:{b:{name:'foo'}}};
const existence = !!_.get(r, 'a.b.name');// !! Convert to the returned value to boolean
console.log(existence); // true
has you can see the _.get secound parameter can be property path like 'a.b.name'
in your case i would do:
!!_.get(this.state, `floor[${this.state.selectedTab}].units.length`);
If the logic to determine whether I should render something or not gets complicated, I will usually extract it to a function rather than leaving it all in the main render's jsx.
renderSomething() {
const { floor, selectedTab } = this.state
if (floor && floor[selectedTab] && floor[selectedTab].units && floor[selectedTab].units.length === 0) {
return <div>render something</div>
}
return null
}
render() {
return (
<div>
{renderSomething()}
{renderSomethingElse()}
</div>
)
}
If you can't assume anything about your state, the above check ought to be safe. Usually, you may be able to assume some things about your state if you are the one controlling the data that would make some of the checks unnecessary. For instance, you may know that it is the case that every value in the floor object always has a units property. Thus, the floor[selectedTab].units would not be required. The extra check obviously doesn't hurt anything, but it can clutter code to always add what would often be redundant checks.
If you're feeling pain keeping track of what values may be undefined and do need extra safety checks, I'd definitely recommend using flow or typescript. Let the computer do a lot of that bookkeeping.
use this function for arrays or nested array (but not for strings)
arr={nested:{nested2:{val:'isset'}}}
if(t=isset(arr,'nested=>nested2=>val')){
alert(t)
}
function isset(obj,nested) {
var dub=obj
var isset=false
if(typeof(obj)!="undefined" && typeof(nested)!="undefined"){
var arr=nested.split('=>');
for(var k in arr){
var key=arr[k];
if(typeof(dub[key])=="undefined"){
isset=false;
break;
}
dub=dub[key];
isset=dub
}
}
return isset;
}
I have a question about array.sort() method in JavaScript. Set of values in the array can vary from 1 to more. Sort function should sort them in the order if there is more than one element. Here is my code:
var myDates = ["03/05/2017","02/01/2017","03/02/2017"];
myDates.sort(function(a,b) {
a = a.split('/').reverse().join('');
b = b.split('/').reverse().join('');
return a > b ? 1 : a < b ? -1 : 0;
});
Code above works fine, all dates are sorted. My question is should I check the length of the array before I run the sort method? I'm asking this because my array can have one element only in some situations. So far my code did not throw any errors when I tested with one element only, but I would like to know if I should check the length of the array before I run the sort() or JavaScript already takes care of that? If anyone knows the answer please let me know. Thank you.
This behaviour is documented in the Array.prototype.sort specification. See http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.sort
Specifically:
The arguments for calls to SortCompare are values returned by a previous call to the [[Get]] internal method, unless the properties accessed by those previous calls did not exist according to HasOwnProperty. If both perspective arguments to SortCompare correspond to non-existent properties, use +0 instead of calling SortCompare. If only the first perspective argument is non-existent use +1. If only the second perspective argument is non-existent use −1.
In short:
Array.prototype.sort((undefined, undefined) => { ... }); // => 0
Array.prototype.sort((undefined, b) => { ... }); // => 1
Array.prototype.sort((a, undefined) => { ... }); // => -1
I'm looking for a way to do the following:
$("#a" || "#b").val() === ""
as opposed to:
$("#a").val() === "" || $("#b").val() === ""
Any ideas?
Thanks in advance!
For two elements, I believe your example is about as short as you can make it and its meaning is clear. However, if you wish to repeat such logic or evaluate more elements, you might be able to improve upon it by creating a simple function to evaluate if any items in a set match a condition.
Extending jQuery
$.fn.any = function (evaluator) {
var items = $(this);
for (var i = 0; i < items.length; i++) {
if (evaluator(items[i]) === true) {
return true;
}
}
return false;
};
Demo: http://jsfiddle.net/xE76y/1/
This is similar to the Any() method implemented in the .Net LINQ library* (and I'm sure is implemented in other libraries, especially those geared towards functional programming). In c#, you would call such a method:
enumerable.Any( o => o.Value == "" );
JavaScript's syntax (sadly) isn't as concise; you end up with something like:
array.any( function(o){ return o.value === ""; } );
So far, this hasn't saved you anything. However, if you want to iterate over a large number of elements, it becomes much more elegant.
// there could be zero inputs or 100 inputs; it doesn't matter
var result = $("input").any(function (o) {
return o.value === "";
});
Native Solution
Note that we aren't relying on jQuery in our any() method. You could also consider a native JavaScript solution such as the Array.some() method.
some() executes the callback function once for each element present in
the array until it finds one where callback returns a true value. If
such an element is found, some immediately returns true.
Demo: http://jsfiddle.net/xE76y/2/
var result = jQuery.makeArray($("input")).some(function (o) {
return o.value === "";
});
Since this is an array method, it only works on an array. This unfortunately means that document.getElementsByTagName("input").some(...) will not work since getElementsByTagName() returns a NodeList.
Of course, you could push whatever you wanted into an array and call some() on that array. The call to jQuery.makeArray() in the example is just for convenience.
Abstracting the Evaluation Functions
Demo: http://jsfiddle.net/xE76y/3/
Perhaps the evaluation functions (such as testing for an empty string) will be reused. These can be abstracted further.
// ideally, this should NOT be left in global scope
function isEmpty(input) {
return input.value === "";
}
// the check now fits nicely in one line.
if ($("input").any(isEmpty)) {
alert("At least one input is empty.");
}
The resulting method calls are quite clean: $("#a, #b").any(isEmpty) and $("input").any(isEmpty)
* Also worth noting that LINQ has been recreated for JavaScript.
Try like this instead:
if ($('#a,#b').is(':empty'))
{
alert("Either a or b is Empty!");
}
Try my demo
Edit:
If it is an input type like a textbox then it would be a little bit bulky but will achieve the same effect:
if ($.inArray("",[ $("#a").val(), $("#b").val() ])>=0)
{
alert("Either a or b is Empty!");
}
See another Demo
If you want to avoid duplication of the empty string "", you could do this:
if ($.inArray([ $("#a").val(), $("#b").val() ], ""))
Or if you only want to select once with jQuery:
if ($.inArray($("#a, #b").map(function() { return this.value; }), ""))
But I wouldn't use either of these myself. They are arguably both less efficient, more contrived, and certainly less readable than the "easy" way!
I'm not an expert in javaScript, but have you cross checked with :
http://api.jquery.com/multiple-selector/
jQuery selector regular expressions
Also, one way would be using the .each function as in
jQuery Multiple ID selectors