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
Related
The .length property on an array will return the number of elements in the array. For example, the array below contains 2 elements:
[1, [2, 3]] // 2 elements, number 1 and array [2, 3]
Suppose we instead wanted to know the total number of non-nested items in the nested array. In the above case, [1, [2, 3]] contains 3 non-nested items, 1, 2 and 3.
Examples
getLength([1, [2, 3]]) ➞ 3
getLength([1, [2, [3, 4]]]) ➞ 4
getLength([1, [2, [3, [4, [5, 6]]]]]) ➞ 6
You can flatten the array using .flat(Infinity) and then get the length. Using .flat() with an argument of Infinity will concatenate all the elements from the nested array into the one outer array, allowing you to count the number of elements:
const getLength = arr => arr.flat(Infinity).length;
console.log(getLength([1, [2, 3]])) // ➞ 3
console.log(getLength([1, [2, [3, 4]]])) // ➞ 4
console.log(getLength([1, [2, [3, [4, [5, 6]]]]])) // ➞ 6
You can use reduce on each array it'll find like this :
function getLength(arr){
return arr.reduce(function fn(acc, item) {
if(Array.isArray(item)) return item.reduce(fn);
return acc + 1;
}, 0);
}
console.log(getLength([1, [2, 3]]))
console.log(getLength([1, [2, [3, 4]]]))
console.log(getLength([1, [2, [3, [4, [5, 6]]]]]))
Recursively count the elements that you don't recurse into:
function getLength(a) {
let count = 0;
for (const value of a) {
if (Array.isArray(value)) {
// Recurse
count += getLength(value);
} else {
// Count
++count;
}
}
return count;
}
Live Example:
function getLength(a) {
let count = 0;
for (const value of a) {
if (Array.isArray(value)) {
count += getLength(value);
} else {
++count;
}
}
return count;
}
console.log(getLength([1, [2, 3]]));
console.log(getLength([1, [2, [3, 4]]]));
console.log(getLength([1, [2, [3, [4, [5, 6]]]]]));
You could just add the lengths for nested array or one.
function getLength(array) {
let count = 0;
for (const item of array) count += !Array.isArray(item) || getLength(item);
return count;
}
console.log(getLength([1, [2, 3]]));
console.log(getLength([1, [2, [3, 4]]]));
console.log(getLength([1, [2, [3, [4, [5, 6]]]]]));
I start by pointing out that this code works. That is not the problem! I just don't understand how really. As I understand it the chunked.push method ads a new array all the time. But obviously, it does not. It gives the right answer:
[[ 1, 2], [3, 4], [5]]
I simply do not understand what is happening in this code. It spits out the right answer and put several items in each array if necessary but the code creates a new subarray each time, no? No, obviously not - but I don't understand why not? Please help!
function chunk(array, size) {
let workArr = [...array];
let chunked = [];
for (let i = 0; i < workArr.length; i++) {
let last = chunked[chunked.length - 1];
if (!last || last.length === size) {
chunked.push([workArr[i]])
} else {
last.push(workArr[i]);
}
}
return chunked;
}
Here is examples of some input parameters and expected results:
// chunk([1, 2, 3, 4], 2) --> [[ 1, 2], [3, 4]]
// chunk([1, 2, 3, 4, 5], 2) --> [[ 1, 2], [3, 4], [5]]
// chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) --> [[ 1, 2, 3], [4, 5, 6], [7, 8]]
// chunk([1, 2, 3, 4, 5], 4) --> [[ 1, 2, 3, 4], [5]]
// chunk([1, 2, 3, 4, 5], 10) --> [[ 1, 2, 3, 4, 5]]
Let's break it
This copies an array there is used a spread operator
let workArr = [...array];
Iterate over every item in workArr array
for (let i = 0; i < workArr.length; i++) {
}
I think this would give you undefined at first run, because there is nothing at index -1 in chunked (because at first, chunked.length is 0), but it will set last to last element of chunked array
let last = chunked[chunked.length - 1];
If last has falsey value (0, null, undefined, "", NaN, false) or length of last equals to size (be aware, that last should be array or string), then push i-th element (indexing from 0) of workArr array into chunked array as an array, else push that element from workArr into last, but last then should be an array
if (!last || last.length === size) {
chunked.push([workArr[i]])
} else {
last.push(workArr[i]);
}
then simply return chunked array
return chunked;
I have an array like this:
var my_array = [[6, 2], [7, 3], [9, 4], [9, 6], [3, 7]]
... and I'd like to sort the array in different groups like below:
var result = [ [6, 2], [7, 3], [9, 4] ],
[ [9, 6], [3, 7] ]
So as you can see the sort method should group all arrays their array[1] values are matching together (like an ascending row)
SO the values in the example above result[0][1] --> 2, result[1][1] --> 3, result[0][3] --> 4 are matching together.
Also the group result[1][0] --> 6 and result[1][1] --> 7 are matching together.
BTW: The my_array - array is already sorted, so that my_array[x][1] <= my_array[x+1][1].
I have no clue how to code this, so this is all what I got till now:
var my_array = [[6, 2], [7, 3], [9, 4], [9, 6], [3, 7]]
function sort_array(array) {
var group=[];
for (var i=array[0][1]; i<3; i++) {
if (array[i+1][1] == i) {
group.push(array[i+1])
}
else {
}
}
return group;
}
console.log(sort_array(my_array));
My understanding of your request;
Take a given array of two item arrays (already sorted by item 2)
group the two item arrays by the sequential item 2's (split them when you encounter a missing int).
return the result.
var my_array = [[6, 2], [7, 3], [9, 4], [9, 6], [3, 7]]
function sort_array(array) {
var results = [];
var tmp = [];
for(var i = 0; i < array.length; i++){
tmp.push(array[i]);
if(i== array.length -1 || array[i][1] != (array[i+1][1]-1)){
results.push(tmp);
tmp = [];
}
}
return results;
}
console.log(sort_array(my_array));
You could do the grouping using recursion, it basically compares the current and the next number, if the next number is consecutive it will continue to call itself, if it's not consecutive it will add a new group then call itself until there is no next value.
"use strict" // this will allow tail call recursion in modern browsers
const my_array = [[5, 0], [6, 2], [7, 3], [9, 4], [9, 6], [3, 7], [4, 10]]
function groupConsecutiveYs([curr, ...rest], acc = [[]]) {
const next = rest[0]
// add to current group
acc[acc.length - 1].push(curr)
if (typeof next === 'undefined') // we are done return the accumulator
return acc
// if next is not consecutive add another grouping
if (curr[1] !== next[1] - 1)
acc.push([])
// call recursive function again
return groupConsecutiveYs(rest, acc)
}
console.log(
groupConsecutiveYs(my_array)
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js?concise=true"></script>
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);
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