Suppose I have arrays parent and child. I want to check if a child exists inside a parent array. The ordering matters.
Example:
parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
child = ["a", "b", "c"]
//returns true
Example:
When parent has a different order:
parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
child = ["a", "b", "c"]
//It should return false
How would I achieve this in Javascript?
Edit: I have tried this How to check if an array contains another array? but it did not work for my case
You can run a loop for child and change the index accordingly. You can also use a match variable to detect change in the sequence.
RETURN TRUE
var parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
var child = ["a", "b", "c"];
var initIndex = parent.indexOf(child[0]);
var match = true;
for(var i=1; i<child.length; i++){
var varIndex = parent.indexOf(child[i]);
if( varIndex === initIndex+1){
initIndex = varIndex;
continue;
}
match = false;
}
console.log(match);
RETURN FALSE
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"];
var initIndex = parent.indexOf(child[0]);
var match = true;
for(var i=1; i<child.length; i++){
var varIndex = parent.indexOf(child[i]);
if( varIndex === initIndex+1){
initIndex = varIndex;
continue;
}
match = false;
}
//return false
console.log(match);
USING STRING OPERATION
You can also convert the array to string to avoid those loop:
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"]
var parentStr = parent.toString();
var match = parentStr.indexOf(child.toString()) !== -1;
//return false
console.log(match);
parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
child = ["a", "b", "c"]
parentStr = parent.toString();
match = parentStr.indexOf(child.toString()) !== -1;
//return true
console.log(match);
Convert the array to string by using JSON.stringify() and remove the square brackets from child string.
Now check the indexOf child in parent to check if it contains the child.
let parent = ["x", "a", "b", "c", "d", "e", "f", "g"];
let child = ["a", "b", "c"];
var parStr = JSON.stringify(parent);
var chldStr = JSON.stringify(child).replace('[', '').replace(']', '')
console.log(parStr.indexOf(chldStr) !== -1);
I wrote a function for this a while back that takes some paramenters:
Array.prototype.containsArray = function (child, orderSensitivity, caseSensitivity, typeSensitivity) {
var self = this;
if (orderSensitivity) return orderSensitiveComparer();
else return orderInsensitiveComparer();
function orderSensitiveComparer() {
var resultArry = [],
placeholder = 0;
if (child.length > self.length) return false;
for (var i = 0; i < child.length; i++) {
for (var k = placeholder; k < self.length; k++) {
if (equalityComparer(self[k], child[i])) {
resultArry.push(true);
if (resultArry.length === child.length) return true;
placeholder = k + 1;
break;
}
else resultArry = [];
}
}
return false;
}
function orderInsensitiveComparer() {
for (var i = 0; i < child.length; i++) {
var childHasParentElement = false;
for (var k = 0; k < self.length; k++) {
if (equalityComparer(child[i], self[k])) {
childHasParentElement = true;
break;
}
}
if (!childHasParentElement) return false;
}
return true;
}
function equalityComparer(a, b) {
if (caseSensitivity && typeSensitivity) return caseSensitiveEq(a, b) && typeSensitiveEq(a, b);
else if (!caseSensitivity && typeSensitivity) return caseInsensitiveEq(a, b) && typeSensitiveEq(a, b);
else if (caseSensitivity && !typeSensitivity) return caseSensitiveEq(a, b) && typeInsensitiveEq(a, b);
else if (!caseSensitivity && !typeSensitivity) return caseInsensitiveEq(a, b) && typeInsensitiveEq(a, b);
else throw "Unknown set of parameters";
function caseSensitiveEq(a, b) {
return a == b;
}
function caseInsensitiveEq(a, b) {
return (a + "").toLowerCase() == (b + "").toLowerCase();
}
function typeSensitiveEq(a, b) {
return typeof(a) === typeof(b);
}
function typeInsensitiveEq(a, b) {
return true;
}
}
}
var parent = [1, 2, 3, "a", "b", "c"];
var child = [1, 2, 3];
var child2 = ["1", "2", "3"];
var child3 = ["A", "b", "C"];
var child4 = ["a", "b", "c"];
var child5 = ["c", "b", "a"];
// Tests:
console.log(parent.containsArray(parent));
console.log(parent.containsArray(child));
console.log(parent.containsArray(child2));
// parent to child 2, order sensitive, not case, not type. => true.
console.log(parent.containsArray(child2, true, false, false));
// parent to child 2, order, not case, type. => false. b/c of type.
console.log(parent.containsArray(child2, true, false, true));
// parent to child 3, order, not case, type. => true.
console.log(parent.containsArray(child3, true, false, true));
// parent to child 4, order, case and type => true.
console.log(parent.containsArray(child4, true, true, true));
// parent to child 4, not order, case and type. => true.
console.log(parent.containsArray(child4, false, true, true));
// parent to child 5, not order case or type => true.
console.log(parent.containsArray(child5));
I have a simple method for small sized arrays of this problem.
First join the array to a string, see Array/join
Search substring, see String/indexOf
parent = ["x", "a", "b", "c", "d", "e", "f", "g"];
child = ["a", "b", "c"];
function matchSubArray(parent, child) {
parentStr = parent.join('');
childStr = child.join('');
return parentStr.indexOf(childStr) != -1;
}
matchSubArray(parent, child);
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"]
if(parent.join("").search(child.join("")) === -1) {
console.log("Not found");
} else {
console.log("found")
}
Related
suppose we have this array :
let a = ["a", "b", "c"]
I need some combination like below:
[["a"], ["b"], ["c"], ["a", "b"], ["a", "c"], ["b", "c"], ["b", "a"], ["c", "a"], ["c","b"], ["a", "b", "c"], ...]
const a = ["a", "b", "c"];
function perm(xs) {
let ret = [];
for (let i = 0; i < xs.length; i = i + 1) {
let rest = perm(xs.slice(0, i).concat(xs.slice(i + 1)));
if (!rest.length) {
ret.push([xs[i]])
} else {
for (let j = 0; j < rest.length; j = j + 1) {
ret.push([xs[i]].concat(rest[j]))
}
}
}
return ret;
}
console.log(perm(a));
feel free to edit this question and if this is a similar question pls duplicate the question .strong text
after searching a while, I foundout there is a function :
function combination(A, comb = [], result = [comb]) {
for (var i = 0; i < A.length; i++)
result = result.concat(combination(A.slice(0, i).concat(A.slice(i + 1)), comb.concat(A[i])));
return result;
}
console.log(combination(["q", "a", "w"]))
and you can delete the first index with .slice(1, array.length)
I have has like this
var hash = {};
hash['a'] = ["a", "b", "c", "d", "e"];
hash['b'] = ["a", "b", "c"];
hash['k'] = ["q", "b"];
Math.max(Object.keys(hash)
.map(function(key) {
return hash[key].length;
})
)
It returns 5 but, I want to get the hash key 'a' at the same time.
Is it possible??
Combine Object.entries() and Array.prototype.reduce() to get the key and the elements behind that key (and their length)
var hash = {
a: ["a", "b", "c", "d", "e"]
,b: ["a", "b", "c"]
,k: ["q", "b"]
};
var result = Object.entries(hash)
.reduce((r, c) => r[1].length > c[1].length ? r : c);
console.log(result);
Does this fulfil your requirement?
I have used sort instead of Math.max here to find the maxima
var hash = {};
hash['a'] = ["a", "b", "c", "d", "e"];
hash['b'] = ["a", "b", "c"];
hash['k'] = ["q", "b"];
var result = Object.keys(hash)
.map(function(key) {
return {[key]: hash[key].length};
}).sort(function(a, b){
return a.key > b.key
})[0]
console.log(result);
i have used this approach for your problem:
var hash = {};
hash['a'] = ["a", "b", "c", "d", "e"];
hash['b'] = ["a", "b", "c"];
hash['k'] = ["q", "b"];
var largestInfo = {
key:'',
length:0
}
Object.keys(hash).map(function(key) {
if(hash[key].length > largestInfo.length){
largestInfo.key = key;
largestInfo.length = hash[key].length;
}
return hash[key].length;
});
console.log(largestInfo);
let's assume that we have two arrays like these:
let s1 = ["A", "B", "C", "D", "B"] // Note: "B" has been occurred 2 times
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"] // // Note: "B" has been occurred 2 times just like s1 but we have another occurrence for "A"
I want to create a new array (let s3) based on these two arrays with this rule that we'll remove the element(s) with occurrences more than the same element's occurrence in array s1
so the s3 array would be like this:
let s3 = ["A", "B", "C", "D", "B", "X", "Y"] // we just removed "A" cause it occurred more than "A" occurances in s1
Note that we want anything else ("X", "Y"). we just want to handle the extra occurrences.
so far I can find the index of repeated occurrences like this but I can't find a way to compare each occurrence to see if it is an extra one or not (complicated):
let s1 = ["A", "B", "C", "D", "B"]
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"]
var s3 = [];
for (let i = 0; i < s2.length; i++) {
for (let j = 0; j < s1.length; j++) {
if (s2[i] === s1[j]) {
s3.push(i);
break;
}
}
}
console.log(s3)
My English is poor and I don't know if I could explain the issue or not!
Note: I can simply use s3 = [...new Set(s2)] to remove repeated elements but I want something else.
Since you want to keep everything originally in s1 but only add items from s2 if they aren't already in you can initially set s3 to s1. Then loop over s2 and if s1 does not have the value then push it into s3.
const s1 = ["A", "B", "C", "D", "B"];
const s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"];
const s3 = [...s1];
s2.forEach(d => {
if (!s1.includes(d)) s3.push(d);
});
console.log(s3);
You can use Map and filter
First Map the array1 to [key, value] format
Iterate over second array, if it's found in Map and value is grater than zero return true else return false,
If it is not found return true
let s1 = ["A", "B", "C", "D", "B"]
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"]
let map = new Map()
s1.forEach(v=>{
if(map.has(v)){
map.set(v,map.get(v)+1)
} else{
map.set(v,1)
}
})
let final = s2.filter(val=>{
if(map.has(val)){
if(map.get(val)){
map.set(val, map.get(val)-1)
return true
}
return false
}
return true
})
console.log(final)
You could count the values of the first set and return the values for a given count or if not known then all items.
var s1 = ["A", "B", "C", "D", "B"],
s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"],
count = s1.reduce((m, v) => m.set(v, (m.get(v) || 0) + 1), new Map),
s3 = s2.filter(v => count.get(v) ? count.set(v, count.get(v) - 1) : !count.has(v));
console.log(...s3);
I have an array like var aa = ["a","b","c","d","e","f","g","h","i","j","k","l"]; I wanted to remove element which is place on even index. so ouput will be line aa = ["a","c","e","g","i","k"];
I tried in this way
for (var i = 0; aa.length; i = i++) {
if(i%2 == 0){
aa.splice(i,0);
}
};
But it is not working.
Use Array#filter method
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
var res = aa.filter(function(v, i) {
// check the index is odd
return i % 2 == 0;
});
console.log(res);
If you want to update existing array then do it like.
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
// variable for storing delete count
dCount = 0,
// store array length
len = aa.length;
for (var i = 0; i < len; i++) {
// check index is odd
if (i % 2 == 1) {
// remove element based on actual array position
// with use of delete count
aa.splice(i - dCount, 1);
// increment delete count
// you combine the 2 lines as `aa.splice(i - dCount++, 1);`
dCount++;
}
}
console.log(aa);
Another way to iterate for loop in reverse order( from last element to first ).
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
// iterate from last element to first
for (var i = aa.length - 1; i >= 0; i--) {
// remove element if index is odd
if (i % 2 == 1)
aa.splice(i, 1);
}
console.log(aa);
you can remove all the alternate indexes by doing this
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
for (var i = 0; i < aa.length; i++) {
aa.splice(i + 1, 1);
}
console.log(aa);
or if you want to store in a different array you can do like this.
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
var x = [];
for (var i = 0; i < aa.length; i = i + 2) {
x.push(aa[i]);
}
console.log(x);
You can use .filter()
aa = aa.filter((value, index) => !(index%2));
You can use temporary variable like below.
var a = [1,2,3,4,5,6,7,8,9,334,234,234,234,6545,7,567,8]
var temp = [];
for(var i = 0; i<a.length; i++)
if(i % 2 == 1)
temp.push(a[i]);
a = temp;
in Ecmascript 6,
var aa = ["a","b","c","d","e","f","g","h","i","j","k","l"];
var bb = aa.filter((item,index,arr)=>(arr.splice(index,1)));
console.log(bb);
const aa = ["a","b","c","d","e","f","g","h","i","j","k","l"];
let bb = aa.filter((items, idx) => idx % 2 !== 0)
I read here that splice has O(N) time complexity. Don't use it in a loop!
A simple alternative for removing odd indexes in place:
for (let idx = 0; idx < aa.length; idx += 2)
aa[idx >> 1] = aa[idx];
aa.length = (aa.length + 1) >> 1;
I use x >> 1 as a shortcut to Math.floor(x/2).
Hi everyone Can't figure out how can I take element from array in a random way and without repeating. Here is my code:
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
"F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
cards = document.getElementsByClassName( "cards" ),
cardBoxes = document.getElementsByClassName( "card-boxes" );
//generate random number
function randomNum( nums ) {
return Math.floor( Math.random() * nums.length );
}
//hide letter behind card in random way
function hideLetter() {
for ( var i = cards.length - 1; i >= 0; i-- ) {
var randomLetter = letters[ randomNum(letters) ];
cards[i].textContent = randomLetter;
};
}
hideLetter();
I take element in a random way, but Math.random repeating themselves. I think I have to write some sort of if statment, which will be detect if element was taken two times, but cant figure how to do it. Looking for advice. Thanks.
Here Codepen of problem http://codepen.io/Kuzyo/pen/vdlai
The sure way is to remove element from the array after it was used. This way it will never be repeated
randomise your array, then walk through the randomised array. This has the benefit of the usual "remove elements while using random indices", while keeping the sequence around in case you need a repeat operation that relies on the same random sorting:
function randomize(array) {
var copy = array.slice(),
random = [],
element, pos;
while(copy.length>0) {
pos = (Math.random()*copy.length) | 0; // bit operation forces 32-bit int
subarray = copy.splice(pos, 1);
random.push(subarray[0]);
}
return random;
}
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
"F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
randomLetters = randomize(letters);
randomLetters.forEach(function(letter) {
// create a card for this letter
});
// do we need it again, in a new random fashion?
// then we can simply call this:
randomLetters = randomize(letters);
Here is my version, with a generator. The function returned by makeRandomGenerator will return random, non-repeating members of inputArray. Once all elements have been used, it will return undefined.
function shuffle(array) {
return array.sort(function() {
return Math.random() > 0.5 ? 1 : -1;
});
}
function makeRandomGenerator(inputArr) {
var arr = inputArr.slice(0);
shuffle(arr);
return function() {
return arr.pop();
}
}
to use:
var letterGenerator = makeRandomGenerator(letters);
function hideLetter() {
for ( var i = cards.length - 1; i >= 0; i-- ) {
var randomLetter = letterGenerator();
if (randomLetter === undefined) {
return;
}
cards[i].textContent = randomLetter;
};
}
hideLetter();
Randomize the array and shift off values from the array :
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E", "F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
cards = document.getElementsByClassName( "cards" ),
i = letters.length, j, temp;
while ( --i ) {
j = Math.floor( Math.random() * (i - 1) );
temp = letters[i];
letters[i] = letters[j];
letters[j] = temp;
}
for ( var i = cards.length; i--; ) {
cards[i].innerHTML = letters.shift();
}
FIDDLE