IndexOf array of several arrays with javascript - javascript

I have an array this way :
var array = [ [1,2] , [2,2,2] , 3 , [3,4] ];
So I want to use indexOf to splice an element.
Example :
var index = array.indexOf( [2,2,2] );
array.splice(index, 1)
Expect =>
array = [ [1,2] , 3 , [3,4] ]
But the problem is that index return -1 (false value).. How to fix that?

The problem is, you have two arrays with the same primitives, but the arrays are not equal.
The comparing works with the object and not with the values inside.
console.log([2, 2, 2] === [2, 2, 2]); // false
var array = [2, 2, 2];
console.log(array === array); // true
If you search for the same array with the same reference to the object, then you get the right index.
var search = [2, 2, 2], // array to serach for
array = [[1, 2], search, 3, [3, 4]], // array with search array
index = array.indexOf(search); // get the index
array.splice(index, 1);
console.log(array); // [[1, 2], 3, [3, 4]]
In ES5, you could search for the index and use a stringified version of the search object for checking with Array#some.
var array = [[1, 2], [2, 2, 2], 3, [3, 4]],
search = [2, 2, 2],
index = -1;
array.some(function(a, i) {
if (JSON.stringify(a) === JSON.stringify(search)) {
index = i;
return true;
}
});
if (index !== -1) {
array.splice(index, 1);
}
console.log(array);
ES6 with Array#findIndex
var array = [[1, 2], [2, 2, 2], 3, [3, 4]],
search = [2, 2, 2],
index = array.findIndex(a => JSON.stringify(a) === JSON.stringify(search));
if (index !== -1) {
array.splice(index, 1);
}
console.log(array)

If you can use a library, you can use the lodash library that exposes a reject function.
Here is a snippet:
var array = [ [1,2] , [2,2,2] , 3 , [3,4] ];
var result = _.reject(array, [2,2,2]);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

var array = [[1, 2], [2, 2, 2], 3, [3, 4]];
var index = array.findIndex(a => JSON.stringify(a) === "[2,2,2]");
alert(index);
if (index > -1) {
array.splice(index, 1);
}
alert(array)
Hope this helps!

indexOf doesn't work because it uses strict equality, so you can't find an array within an array unless you have a reference to the array you're trying to find.
As an alternative, you can use a plain old ed 3 for loop and compare stringified values:
var array = [ [1,2] , [2,2,2] , 3 , [3,4] ];
function findIndex(arr, value) {
for ( var i=0, value=String(value), iLen=arr.length; i<iLen; i++) {
if (String(arr[i]) == value) return i;
}
return -1;
}
console.log(findIndex(array, [2,2,2])); // 1

Related

Javascript - Create dynamic index of numeric array index

I have an array like this
var a= [[1, 2, [6, 7, 8]], 4, 5];
and another array that indicates a specific element by describing the index:
var index= [0, 2, 2 ]; // = 8 in a
What i need is use variable "index" to create the index of "a" and replace the correspondent element (8) with another value, for example "hello".
How can i do?
Use Array.reduce() to iterate the index array without the last element (using Array.slice()), and get the sub array. Splice the text to last index inside the sub array:
const index = [0, 2, 2 ]; // = 8 in a
const a = [[1, 2, [6, 7, 8]], 4, 5];
const updateIndex = (arr, index, replacement) => {
index
.slice(0, -1)
.reduce((c, i) => c[i], arr)
.splice(index[index.length -1], 1, replacement);
}
updateIndex(a, index, 'hello');
console.log(a);
Basically each index of index array represents a level of nesting and the value at index represents the index of array in which target element lies or the index of target element itself if it is last element of array index. The problem can be easily solved recursively
For simplicity, I am calling index array, path
var path = [0, 2, 2]
var values = [[1, 2, [6, 7, 8]], 4, 5];
function findValues(path, values) {
//base case, if length = 1 we have the index of target element
if(path.length == 1) {
var targetIndex = path[0]
//read it
console.log(values[path]) //8
// modify it
values[path] = 'hello'
} else {
// pick the current nesting level
var currentLevel = path.shift()
// go one level down
findValues(path, values[currentLevel])
}
}
findValues(path, values)
console.log(values) // [[1, 2, [6, 7, "hello"]], 4, 5]
Ofcouse the function assumes that path and values array are in valid state i.e. target element exists on the given path, you might want to modify this function to validate input and handle edge cases
You can create a function that accesses the desired array and changes the value.
Take a look:
var index = [0, 2, 2 ]; // = 8 in a
var a = [[1, 2, [6, 7, 8]], 4, 5];
function updateIndex(arr, index, value) {
var elementIndex = index.pop();
var tempArray = a;
index.forEach(item => tempArray = tempArray[item]);
tempArray[elementIndex] = value;
}
updateIndex(a, index, 'hello');
console.log(a);
You could take a function which uses a vopy of indices and save the last index for accessing the reduced array for assignment of the value.
This proposal creates missing arrays as well.
function setValue(array, [...indices], value) {
var last = indices.pop();
indices.reduce((a, i) => a[i] = a[i] || [], array)[last] = value;
}
var array = [[1, 2, [6, 7, 8]], 4, 5];
setValue(array, [0, 2, 2 ], 'hello'); // targetting 8
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to only allow an array to be pushed into an array once?

I have an array that has other arrays in it which have been pushed in. For an example:
const Arrays = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3] ];
let myArr = [];
Arrays.map(arr => {
if(myArr.indexOf(arr)){
return
}
myArr.push(arr)
})
const myArr = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3] ];
In this array you can see that there are two arrays with the same set of numbers 1, 2 and 3. I want to somehow set a condition saying:
If this array already exist then do not add this array in any order again to prevent this from happening. So that when it comes in the loop that this set of numbers comes up again it will just skip over it.
You can use some() and every() methods to check if same array already exists before push().
const myArr = [ [1,2,3], [4,5,6], [7,8,9] ];
let input = [2,1,3]
function check(oldArr, newArr) {
return oldArr.some(a => {
return a.length == newArr.length &&
a.every(e => newArr.includes(e))
})
}
if(!check(myArr, input)) myArr.push(input)
console.log(myArr)
You can make temp array with sorted element with joined and check by indexOf
const myArr = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3],[6,5,4] ];
var newArr = [];
var temp = [];
for(let i in myArr){
let t = myArr[i].sort().join(",");
if(temp.indexOf(t) == -1){
temp.push(t);
newArr.push(myArr[i]);
}
}
console.log(newArr);
The accepted answer does not respect the special case where only two values are in the array and the array has to check against two values in a different count like
[1, 1, 2]
and
[1, 2, 2]
which are different arrays.
For a working solution, I suggest to use a Map and count the occurences of same values of the first array and subtract the count of the values for the other arrray.
As result return the check if all elements of the Map are zero.
function compare(a, b) {
var map = new Map;
a.forEach(v => map.set(v, (map.get(v) || 0) + 1));
b.forEach(v => map.set(v, (map.get(v) || 0) - 1));
return [...map.values()].every(v => !v);
}
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [2, 1, 3], [1, 1, 2], [1, 2, 2], [2, 1, 1], [2, 1, 2]],
unique = array.reduce((r, a) => (r.some(b => compare(a, b)) || r.push(a), r), []);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way is to sort them numerically with .sort() then compare them.

How to get the last array that includes a certain element?

I have an array of arrays and I want to check if there is a tie between the second elements and then return the first element of the last array that makes a tie.
for example this should return 4. (the first element in the last array that has a second element that makes a tie)
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
It is quite simple, you need to iterate over your source array, check if the given item matches the criteria, and save it to result if it does. Now if any other item does match the criteria, result's value will be overwritten with the new matching item.
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result;
optionsArray.forEach(function(item) {
if(item[1] == 10) {
result = item;
}
});
console.log(result);
You can create a simple find function that iterates the array backwards, and returns as soon as a condition callback returns true.
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
function find10(s) {
return s[1] === 10;
}
function findFromTheEnd(arr, cb) {
var l = arr.length;
while(l--) { // iterate backwards
if(cb(arr[l])){ // if the callback returns true
return arr[l]; // return the item
}
}
return null; // return null if none found
}
var result = findFromTheEnd(optionsArray, find10);
console.log(result);
You can use reduceRight() and return array.
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result = arr.reduceRight(function(r, e) {
if(e[1] == 10 && !r) r = e;
return r;
}, 0)
console.log(result)
You can also use for loop that starts from end and break on first match.
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result;
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i][1] == 10) {
result = arr[i]
break;
}
}
console.log(result)
A classic for in the reserve order with a break seems enough :
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var elementFound;
for (var i = optionsArray.length-1; i >=0; i--) {
if(optionsArray[i].item[1] == 10) {
elementFound = optionsArray[i].item[1];
break;
}
}
If elementFound is not undefined, it refers to the found array.
Rather than considering this as a multidimensional array problem, think of it as an array includes problem nested in an array search problem;
const aarr = [1, 2, 3, 4];
aarr.includes(3); // true
aarr.includes(10); // false
// and
const barr = ['hello', 'world'];
barr.find(item => item[0] === 'h'); // "hello"
barr.find(item => item[3] === 'l'); // "hello"
barr.find(item => item[1] === 'z'); // undefined
So to nest these,
const carr = [[1, 2, 3, 4], [4, 5, 6, 7]];
carr.find(arr => arr.includes(4)); // [1, 2, 3, 4]
carr.find(arr => arr.includes(6)); // [4, 5, 6, 7]
Next, we've reduced the whole problem down to "how to do this in reverse?"
You've a few options depending on how you want to implement it, but a simple way to do it is a shallow clone arr.slice() followed by a reverse arr.reverse() (we use the clone so there are no side-effects of reverse on the original array)
carr.slice().reverse().find(arr => arr.includes(4)); // [4, 5, 6, 7]
If you're working with an index, remember that you'll need to transform those too; -1 is fixed, otherwise transformed_index = arr.length - original_index - 1
Here is how you might implement the reverse of some of the Array methods
const optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
// index 0 1 2 3 4
function arrLast(arr, comparator, method = 'find', transform = x => x) {
return transform(arr.slice().reverse()[method](comparator), arr);
}
const findLast = (arr, comparator) => arrLast(arr, comparator);
const findLastIndex = (arr, comparator) => arrLast(arr, comparator, 'findIndex', (i, arr) => i === -1 ? -1 : arr.length - i - 1);
arrLast(optionsArray, arr => arr.includes(10)); // [4, 10]
findLastIndex(optionsArray, arr => arr.includes(10)); // 3
If you have to make comparisons among array items and you need to cut short once you are satisfied a while loop is ideal. Accordingly you may do as follows;
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]],
i = 0,
result;
while (arr[i][1] === arr[++i][1]);
result = arr[i-1][0]
console.log(result);

Javascript comparing multiple arrays to get unique value across all

I have the following array:
var array = [
[1, 2, 3, 4, 5],
[2, 3],
[3, 4],
[3]
];
I'm trying to end up with a unique set of numbers from the arrays that appear in all arrays.
Therefore in this case returning
[3]
Any suggestions?
Many thanks :)
Store the value of array[0] in a variable (let's call it result).
Loop from array[1] to the end.
In this loop, run through all the values of result. If the current value of result is not in array[x] remove this value from result.
At the end of the loop, result only contains the desired values.
Aside from the obvious "iterate over every array and find matching numbers in every other array" you could flatten (concat) the original array, sort it, then look for numbers that occur at four consecutive indexes. I'm not a fan of questions where OP doesn't show any effort, but this was quite fun, so here it goes
array.reduce(function(prev, cur){
return prev.concat(cur);
})
.sort()
.filter(function(item, i, arr){
return arr[ i + array.length - 1 ] === item;
});
Or ES2015:
array.reduce((prev, cur)=>prev.concat(cur))
.sort()
.filter((i, idx, arr)=>(arr[idx+array.length-1]===i));
After learning i was using the wrong javascript method to remove from an array (pop) and some more tinkering. I got it working many thanks for those who responded.
var array = [
[2, 3, 5, 1],
[3, 4, 2, 1],
[3, 2],
[3, 4, 2, 5]
];
var result = array[0]
for (var i = 1; i < array.length; i++) {
for (var j = 0; j < result.length; j++) {
var arrayQuery = $.inArray(result[j], array[i]);
if(arrayQuery == -1){
result.splice(j, 1)
}
};
};
Try this:
var array = [
[1, 2, 3, 4, 5],
[2, 3],
[3, 4],
[3]
];
var arr = [];
for(var x in array){
for(var y in array[x]){
if(arr.indexOf(array[x][y]) === -1){
arr.push(array[x][y]);
}
}
}
console.log(arr);
Output:
[1, 2, 3, 4, 5]
Working Demo

Permutation Javascript

So I have this code now, and in input I have in ascending order my name's letters "ahimrsu". I need to show up the right number for "mariush" from all combinations which should to be 2170. For now it only show ahimrsu, ahimrus, ahimsru, ahimsur, ahimurs, ahimusr, ahirmus, ahirmsu.... etc How can I do this?
<!DOCTYPE HTML>
<html>
<head>
<!--Script Function Start Here-->
<script type="text/javascript">
function perms(data) {
if (!(data instanceof Array)) {
throw new TypeError("input data must be an Array");
}
data = data.slice(); // make a copy
var permutations = [],
stack = [];
function doPerm() {
if (data.length == 0) {
permutations.push(stack.slice());
}
for (var i = 0; i < data.length; i++) {
var x = data.splice(i, 1);
stack.push(x);
doPerm();
stack.pop();
data.splice(i, 0, x);
}
}
doPerm();
return permutations;
}
var input = "ahimrsu".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
result[i] = result[i].join('');
}
console.log(result);
</script>
<!--Header start here-->
</head>
<body>
<!--Script Result-->
<script type="text/javascript">
document.write(result);
</script>
</body>
</html>
This is my solution from the following answer: https://stackoverflow.com/a/18879232/783743
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
You can use the permute function to find all the permutations of an array:
var array = "ahimrsu".split("");
var permutations = permute(array).map(join);
var index = permutations.indexOf("maruish");
function join(array) {
return array.join("");
}
The algorithm is very simple to understand:
We want a function permute of the type [a] -> [[a]] (i.e. given a list of as it returns a list of permutations of the input).
Given the empty list ([]) an an input, the output is an empty list of permutations ([[]]).
Otherwise for every element:
We remove the element from the list.
We recursively find the permutations of the remaining elements.
We add the element we removed to the beginning of every permutation.
For example, suppose we want to find the permutation of the array [1, 2, 3]:
1. permute([1, 2, 3]) === [1, 2, 3].reduce(permutate, [])
1. permutate([], 1, 0, [1, 2, 3])
1. permute([2, 3]) === [2, 3].reduce(permutate, [])
1. permutate([], 2, 0, [2, 3])
1. permute([3]) === [3].reduce(permutate, [])
1. permutate([], 3, 0, [3])
1. permute([]) === [[]]
2. [[]].map(concat, [3]) === [[3]]
3. [].concat([[3]]) === [[3]]
2. [[3]].map(concat, [2]) === [[2, 3]]
3. [].concat([[2, 3]]) === [[2, 3]]
2. permutate([[2, 3]], 3, 1, [2, 3])
1. permute([2]) === [2].reduce(permutate, [])
1. permutate([], 2, 0, [2])
1. permute([]) === [[]]
2. [[]].map(concat, [2]) === [[2]]
3. [].concat([[2]]) === [[2]]
2. [[2]].map(concat, [3]) === [[3, 2]]
3. [[2, 3]].concat([[3, 2]]) === [[2, 3], [3, 2]]
2. [[2, 3], [3, 2]].map(concat, [1]) === [[1, 2, 3], [1, 3, 2]]
3. [].concat([[1, 2, 3], [1, 3, 2]]) === [[1, 2, 3], [1, 3, 2]]
2. permutate([[1, 2, 3], [1, 3, 2]], 2, 1, [1, 2, 3])
1. permute([1, 3]) === [1, 3].reduce(permutate, [])
2. [[1, 3], [3, 1]].map(concat, [2]) === [[2, 1, 3], [2, 3, 1]]
3. [[1, 2, 3], [1, 3, 2]].concat([[2, 1, 3], [2, 3, 1]])
3. permutate([[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]], 3, 2, [1, 2, 3])
1. permute([1, 2]) === [1, 2].reduce(permutate, [])
2. [[1, 2], [2, 1]].map(concat, [3]) === [[3, 1, 2], [3, 2, 1]]
3. [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]].concat([[3, 1, 2], [3, 2, 1]])
Old explanation:
First we remove the first element of the list. Hence we have item 1 and list [2, 3].
Next we find the permutations of [2, 3].
We remove the first element. Hence we have item 2 and list [3].
Next we find the permutations of [3].
We remove the first element. Hence we have item 3 and list [].
Next we find the permutations of [] which is [[]].
We add 3 to the beginning of each permutation.
The result is [[3]].
We add 2 to the beginning of each permutation.
The result is [[2, 3]].
We remove the second element. Hence we have item 3 and list [[2]].
Next we find the permutations of [2].
We remove the first element. Hence we have item 2 and list [].
Next we find the permutations of [] which is [[]].
We add 2 to the beginning of each permutation.
The result is [[2]].
We add 3 to the beginning of each permutation.
The result is [[3, 2]].
We combine the two two lists.
The result is [[2, 3], [3, 2]].
We add 1 to the beginning of each permutation.
The result is [[1, 2, 3], [1, 3, 2]].
Same for the second element: item 2 and list [1, 3].
Same for the third element: item 3 and list [1, 2].
We combine the three lists.
The result is [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]].
See the demo:
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
var array = "ahimrsu".split("");
var permutations = permute(array).map(join);
var index = permutations.indexOf("maruish");
alert("maruish is the " + (index + 1) + "th permutation of ahimrsu.");
function join(array) {
return array.join("");
}
Hope that helps.
Algorithm for string permutation will be a little bit more complicated with recursive step (it's possible to code it without recursion though).
The next javascript implementation is based on the description of the algorithm from this answer:
Remove the first letter
Find all the permutations of the remaining letters (recursive step)
Reinsert the letter that was removed in every possible location.
Implementation then something like this:
function permutation(str) {
if (str.length == 1) {
return [str];
}
var first = str[0], // Step #1
perms = permutation(str.slice(1)), // Step #2
result = [];
// Step #3
for (var i = 0; i < perms.length; i++) {
for (var j = 0; j <= perms[i].length; j++) {
result.push( perms[i].slice(0, j) + first + perms[i].slice(j) );
}
}
return result;
}
console.log(permutation('ahimrsu'));
Above implementation gives 5040 combinations, which seems to be correct, since 7! == 5040 (number of permutations is a factorial of the number of chars).
Now when you have all possible permutations array you can easily find specific string occurrence:
var combinations = permutation('ahimrsu');
var index = combinations.indexOf('mariush'); // Index of the "mariush"
alert('"mariush" is the ' + (index + 1) + 'th permutation of "ahimrsu".');
Well, 'mariush' is actually permutation 2220 if we are
using your ordering scheme:
/*jslint white: true*/
var perm = function(s){
'use strict';
if(s.length === 1){
return [s];
}
// For each character c in s, generate the permuations p of all
// the other letters in s, prefixed with c.
return [].reduce.call(s, function(p,c,i){ // permutations, char, index
var other = s.slice(0,i) + s.slice(i+1);
return p.concat(perm(other).map(function(oneperm){
return c + oneperm;
}));
}, []);
};
alert(perm('ahimrsu').indexOf('mariush') + 1); // 2220

Categories

Resources