array of arrays who's objects' indices grow progressively - javascript
Simplified Version
for...
ar = [
{"element":"a","index":0},
{"element":"b","index":1},
{"element":"e","index":4},
{"element":"d","index":3}
];
should return...
ans = [[
{"element":"a","index":0},
{"element":"b","index":1},
{"element":"e","index":4}],
[{"element":"a","index":0},
{"element":"b","index":1},
{"element":"d","index":3}]
];
It could return arrays of just {"element":"e","index":4} and just {"element":"d","index":3} since there is nothing behind it, but it's not necessary.
Original
I have this array of elements...
ar = [
{"element":"c","index":2},
{"element":"a","index":0},
{"element":"b","index":1},
{"element":"e","index":4},
{"element":"d","index":3}
];
I'd like to return an array of arrays which contain sequences where the "index"'s of each object grow progressively, and have the max number of objects for which obj1[index] < nextobj[index].
i.e. it should return..
[
[{"element":"c","index":2}, {"element":"e","index":4}],
[{"element":"c","index":2}, {"element":"d","index":3}],
[{"element":"a","index":0}, {"element":"b","index":1}, {"element":"d","index":3}],
[{"element":"a","index":0}, {"element":"b","index":1}, {"element":"e","index":4}]
[{"element":"d","index":3}],
[{"element":"e","index":4}]
]
I've tried using ar.reduce but am not that familiar with it and don't know if it's appropriate for this instance.
Not sure why these are not listed in your example
[{ element="a", index=0}, { element="e", index=4}]
[{ element="a", index=0}, { element="d", index=3}]
[{ element="b", index=1}, { element="e", index=4}]
[{ element="b", index=1}, { element="d", index=3}]
but here is what could produce something close
var ar = [
{"element":"c","index":2},
{"element":"a","index":0},
{"element":"b","index":1},
{"element":"e","index":4},
{"element":"d","index":3}
];
var results = [];
traverse([], 0);
function traverse(r, startIdx)
{
if (startIdx >= ar.length){
console.log(r);
return;
}
for (var i = startIdx; i < ar.length ; i++){
if ((startIdx == 0) || (r[r.length - 1].index) <= ar[i].index) {
rCopy = r.slice(0);
rCopy.push(ar[i]);
traverse(rCopy, i + 1);
}
else if (r.length > 0) {
console.log(r);
}
}
}
JSFiddle1, JSFiddle2
var ar = [
{"element":"c","index":2},
{"element":"a","index":0},
{"element":"b","index":1},
{"element":"e","index":4},
{"element":"d","index":3}
];
var results = [];
traverse([], 0);
collapse(results);
//console.log(results);
for (var i = results.length - 1; i >= 0; i--) {
console.log(results[i]);
}
function traverse(r, startIdx) {
if (startIdx >= ar.length) {
results.push(r);
return;
}
for (var i = startIdx; i < ar.length ; i++) {
if ((startIdx == 0) || (r[r.length - 1].index) <= ar[i].index) {
rCopy = r.slice(0);
rCopy.push(ar[i]);
traverse(rCopy, i + 1);
}
else if (r.length > 0) {
results.push(r);
}
}
}
function collapse() {
for (var i = results.length - 1; i >= 0; i--) {
for (var j = results.length - 1; j >= 0; j--) {
if ((i !== j) && (contains(results[i], results[j]))) {
results[i].remove = true;
}
}
}
for (var i = results.length - 1; i >= 0; i--) {
if (results[i].remove) {
results.splice(i, 1);
}
}
}
// Checks if set1 is contained within set2
function contains(set1, set2) {
for (var i = 0; i < set1.length; i++) {
var found = false;
for (var j = 0; j < set2.length; j++) {
if (set1[i].index === set2[j].index) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
JSFiddle3
Related
Loop failure, values are not cleared when element = maximum a bug is displayed
I am iterating over the matrix object. Which I create inside the loop, then I modify its values through the increment. When the increment reaches its maximum (51), I have to go back to the outer loop and create a new object one more element. Example: {0: 0, 1: 0}. Now I iterate over the last element in the object, if it = maximum, I go to the next one, from "1" to "0", and increment "0", and "1" = 0. Then I have to iterate over "1". But the values are not cleared when element = maximum a bug is displayed. const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; function check(maxLength) { for (let matrixLength = 0; matrixLength < maxLength; matrixLength++) { let a = matrix(matrixLength); let Indx; while (Indx!==null) { Indx = getIndex(a,letters.length); console.log(increment(a,Indx,Indx)); } } } function matrix(length) { let matrix = {}; for (let i = 0; i <= length; i++) { matrix[i] = 0; } return matrix; } function getIndex(matrix, arrLength) { for (let i = Object.values(matrix).length - 1; i >= 0; i--) { if (matrix[i]!==arrLength - 1) { return i; } } console.log('null'); return null; } function increment(matrix, index, prevIndex = null) { matrix[index]++; if (prevIndex === null || index === prevIndex) { return matrix; } for (let i = index + 1; i < Object.values(matrix).length; i++) { matrix[i] = 0; } return matrix; } check(3);
Check whether Indx is null after calling getIndex, not before the next iteration. const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; function check(maxLength) { for (let matrixLength = 0; matrixLength < maxLength; matrixLength++) { let a = matrix(matrixLength); while (true) { let Indx = getIndex(a, letters.length); if (Indx == null) { break; } console.log(increment(a, Indx, Indx)); } } } function matrix(length) { let matrix = {}; for (let i = 0; i <= length; i++) { matrix[i] = 0; } return matrix; } function getIndex(matrix, arrLength) { for (let i = Object.values(matrix).length - 1; i >= 0; i--) { if (matrix[i] !== arrLength - 1) { return i; } } console.log('null'); return null; } function increment(matrix, index, prevIndex = null) { matrix[index]++; if (prevIndex === null || index === prevIndex) { return matrix; } for (let i = index + 1; i < Object.values(matrix).length; i++) { matrix[i] = 0; } return matrix; } check(3);
CodeWars sorting numbers and letters
I am currently doing a codewars problem, and I think I almost got it however, I ran across a problem when sorting index values with the same letter. link to problem is here. https://www.codewars.com/kata/5782dd86202c0e43410001f6 function doMath(s) { let strSplit = s.split(' '); let clonedArr = strSplit.slice(); for (let i = 0; i < strSplit.length; i++) { for (let j = 0; j < strSplit[i].length; j++) { let current = strSplit[i][j]; if (isNaN(current)) { let letter = current; strSplit[i] = strSplit[i].replace(letter, ''); strSplit[i] = letter + strSplit[i]; } } } let sortedArr = strSplit.sort(); console.log(sortedArr); // ["b900", "y369", "z123", "z246", "z89"] let noLetterArr = sortedArr.map(x => { return x.slice(1); }); let numberArr = noLetterArr.map(y => { return +y; }) let firstEl = numberArr[0]; for (let i = 1; i < numberArr.length; i++) { if (numberArr.indexOf(numberArr[i]) % 4 == 1) { firstEl += numberArr[i]; } if (numberArr.indexOf(numberArr[i]) % 4 == 2) { firstEl -= numberArr[i]; } if (numberArr.indexOf(numberArr[i]) % 4 == 3) { firstEl *= numberArr[i]; } } return firstEl; } console.log(doMath('24z6 1z23 y369 89z 900b')); I would like to sort the sortedArr the ones with the same letter by how they first appeared in string. So since "z246" appeared first in the original string. I would like to have that before "1z23". I had a hard time creating a function for that.
var al = []; function doMath(s) { var ar = s.split(" "); for (let i = 0; i < ar.length; i++) { for (let char of ar[i]) { let temp = char.match(/[a-z]/i); if (temp) { al[i] = char; ar[i] = ar[i].replace(char, ''); ar[i] = char + ar[i]; } } } al = al.sort(); //New Sort Logic to pass above test case and others too var n = []; for (let i = 0; i < al.length; i++) { for (let j = 0; j < ar.length; j++) { if (ar[j].startsWith(al[i]) && !n.includes(ar[j])) { n.push(ar[j]); } } } var result = parseInt(n[0].substr(1)), count = 1; for (let i = 1; i < n.length; i++) { if (count == 1) { result = result + parseInt(n[i].substr(1)); count++; } else if (count == 2) { result = result - parseInt(n[i].substr(1)); count++; } else if (count == 3) { result = result * parseInt(n[i].substr(1)); count++; } else if (count == 4) { result = result / parseInt(n[i].substr(1)); count = 1; } } return Math.round(result); }
how to get the count value based on comparing string in javascript
I have array object in which I compare each string in a array and if one letter is not matching, increment the value. If three characters match with the string then increment the count value, else 0 var obj = ["race", "sack", "grass", "brass", "beat", "pack", "cake"] fucntion getValue(obj) { var count = 0 for (var i = 0; i <= obj.length; i++) { for (var j = 1; j <= obj.length; j++) { if (obj[i].split("") == obj[j].split("") { count++; } } } } Expected Output race 1 sack 2 // (pack, cake matches 3 letters with sack so 2) grass 1 brass 1 beat 0 pack 2 cake 3
function getSameCount(str1, str2) { let count = 0; const obj = str2.split(""); for(str of str1){ let idx = obj.findIndex(s => s === str); if(idx >= 0){ count++; obj.splice(idx, 1); } } return count; } var obj = ["race", "sack", "grass", "brass", "beat", "pack", "cake"] const res = {} for (var i = 0; i < obj.length; i++) { res[obj[i]] = 0 for (var j = 0; j < obj.length; j++) { if (i != j) { matchCount = getSameCount(obj[i], obj[j]) if (matchCount === 3) { res[obj[i]]++ } else { if (obj[i].length - matchCount == 1) { res[obj[i]]++ } } } } } console.log(res)
You can create an object for output, parse through each element in the array, replace characters from comparing elements. check if at least 3 chars got removed if so +1 to respective element. const arr = ["race", "sack", "grass", "brass", "beat", "pack", "cake"]; const out = Object.fromEntries(arr.map(e => [e, 0])); for(i in arr) { for(j in arr) { if(i == j) continue; if(arr[i].length !== arr[j].length) continue; const res = [...arr[i]].reduce((acc, e)=> acc.replace(e, ''), arr[j]); if(res.length <= arr[j].length - 3) { out[arr[i]] = out[arr[i]] + 1 } } } console.log(out);
How to get all possible combinations of elements in an array including order and lengths
function getAllCombinations(arr) { var f = function(arr) { var result = []; var temp = []; for (var i = 0; i < arr.length; i++) { temp = []; temp.push(arr[i]); result.push(temp); for (var j = 0; j < arr.length; j++) { if (j != i) { temp = []; temp.push(arr[i]); temp.push(arr[j]); result.push(temp); for (var k = 0; k < arr.length; k++) { if (k != i && k != j) { temp = []; temp.push(arr[i]); temp.push(arr[j]); temp.push(arr[k]); result.push(temp); for (var l = 0; l < arr.length; l++) { if (l != i && l != j && l != k) { temp = []; temp.push(arr[i]); temp.push(arr[j]); temp.push(arr[k]); temp.push(arr[l]); result.push(temp); } } } } } } } return result; } return f(arr); } //call this function console.log(getAllCombinations(["a", "b", "c", "d"])); [["a"],["a","b"],["a","b","c"],["a","b","c","d"],["a","b","d"],["a","b","d","c"],["a","c"],["a","c","b"],["a","c","b","d"],["a","c","d"],["a","c","d","b"],["a","d"],["a","d","b"],["a","d","b","c"],["a","d","c"],["a","d","c","b"],["b"],["b","a"],["b","a","c"],["b","a","c","d"],["b","a","d"],["b","a","d","c"],["b","c"],["b","c","a"],["b","c","a","d"],["b","c","d"],["b","c","d","a"],["b","d"],["b","d","a"],["b","d","a","c"],["b","d","c"],["b","d","c","a"],["c"],["c","a"],["c","a","b"],["c","a","b","d"],["c","a","d"],["c","a","d","b"],["c","b"],["c","b","a"],["c","b","a","d"],["c","b","d"],["c","b","d","a"],["c","d"],["c","d","a"],["c","d","a","b"],["c","d","b"],["c","d","b","a"],["d"],["d","a"],["d","a","b"],["d","a","b","c"],["d","a","c"],["d","a","c","b"],["d","b"],["d","b","a"],["d","b","a","c"],["d","b","c"],["d","b","c","a"],["d","c"],["d","c","a"],["d","c","a","b"],["d","c","b"],["d","c","b","a"]] A total of 64 combinations for a 4 length array. The function works fine but I need to make this function recursive. The for loops have to be nested based on the length of the array and the push also increased per nested loop. Really appreciate some advice.
Finally made it recursive !! Tried to work down on the the original code posted above moving each loop functionality into simple functions. function getAllCombinations(inputArray) { var resultArray = []; var combine = function() { for (var i in inputArray) { var temp = []; var tempResult = []; for (var j in arguments) { tempResult.push(inputArray[arguments[j]]); if (arguments[j] == i) { temp = false; } else if (temp) { temp.push(arguments[j]); } } if (temp) { temp.push(i); combine.apply(null, temp); } } if (tempResult.length > 0) { resultArray.push(tempResult); } return resultArray; }; return combine(); } See the older version here. Result produces 64 unique combinations for a 4 dimensional array console.log(getAllCombinations(["a", "b", "c", "d"])); [["a","b","c","d"],["a","b","c"],["a","b","d","c"],["a","b","d"],["a","b"],["a","c","b","d"],["a","c","b"],["a","c","d","b"],["a","c","d"],["a","c"],["a","d","b","c"],["a","d","b"],["a","d","c","b"],["a","d","c"],["a","d"],["a"],["b","a","c","d"],["b","a","c"],["b","a","d","c"],["b","a","d"],["b","a"],["b","c","a","d"],["b","c","a"],["b","c","d","a"],["b","c","d"],["b","c"],["b","d","a","c"],["b","d","a"],["b","d","c","a"],["b","d","c"],["b","d"],["b"],["c","a","b","d"],["c","a","b"],["c","a","d","b"],["c","a","d"],["c","a"],["c","b","a","d"],["c","b","a"],["c","b","d","a"],["c","b","d"],["c","b"],["c","d","a","b"],["c","d","a"],["c","d","b","a"],["c","d","b"],["c","d"],["c"],["d","a","b","c"],["d","a","b"],["d","a","c","b"],["d","a","c"],["d","a"],["d","b","a","c"],["d","b","a"],["d","b","c","a"],["d","b","c"],["d","b"],["d","c","a","b"],["d","c","a"],["d","c","b","a"],["d","c","b"],["d","c"],["d"]]
Here is my solution using a subroutine, and closures. Also slice is very useful here. If you found this helpful, or if you think other people will find this helpful, don't be afraid to upvote. function getMyCombinations(coll) { const result = []; (function search(currentPerm, letters) { if (letters.length === 0) return result.push(currentPerm); let trimArray = letters.slice(1); letters.forEach(letter => search(currentPerm + letter, trimArray)); })('', coll) return result; } console.log(getMyCombinations(["a", "b", "c", "d"])); I have refactored my original answer to better align with the users request. function findPerm(array, currentPerm = '', result =[]) { if (array.length === 0) return result; let trimArray = array.slice(1); array.forEach(v => { let copy = [...result]; let perm = (currentPerm + v).split(''); let res = copy.push(perm); result = findPerm(trimArray, currentPerm + v, copy); }); return result; }; console.log(findPerm(['a', 'b', 'c', 'd']));
An alternative solution, seems getting the desired output :) console.log(JSON.stringify(getMyCombinations(["a", "b", "c", "d"]))) function getMyCombinations(arry) { var len = arry.length; var tempArray = []; var result = [] var tempCount = 1; var createCombinations = function(count){ var singleLevelArray = []; arry.forEach(function(item){ if(count){//1 if(count > 1){ for(var j = 0; j < tempArray.length; j++){ if(tempArray[j].indexOf(item) === -1){ var x = tempArray[j].slice(); x.push(item); singleLevelArray.push(x); result.push(x); } } } else { for(var k = 0; k < len; k++){ if(item.indexOf(arry[k]) === -1){ tempArray.push([item, arry[k]]); result.push([item, arry[k]]); } } } } else { result.push([item]); } }) if(singleLevelArray.length){ tempArray = [] tempArray = singleLevelArray; } if(tempCount < len){ createCombinations(tempCount++); } return result; } return createCombinations() }
How to compare two arrays in JavaScript?
If I have two arrays as parameters how can I find the starting index where the second parameter occurs as a sub-array in the array given as the first parameter. E.g.: [5,9,3,6,8], [3,6] should return 2. Is there a function in JavaScript for this, or does it just loop through both of them and compare?
findArrayInArray = function(a, b) { var ai = a.length , bi = b.length; for(var i=0; i<ai; i++) { if (a[i] === b[0]) { if(bi === 1) return i; for(var x=1; x<bi; x++) { if(a[i+x] === b[x]) { if(x === bi-1) return i; } else { break; } } } } } var arr1 = [5,9,3,6,8]; var arr2 = [3,6]; console.log(findArrayInArray(arr1,arr2)); // 2 http://jsfiddle.net/ymC8y/3/
In direct answer to your question, there is no built in function in JS to look in an array for a sub-array. You will have to do some sort of brute force looping search like this or use some external library function that already has array comparison logic. Here's what a brute force solution in plain JS looks like: function findSubArrayIndex(master, sub) { for (var m = 0; m < master.length - sub.length + 1; m++) { for (var s = 0; s < sub.length; s++) { if (master[m + s] !== sub[s]) { break; } else if (s === sub.length - 1) { return m; } } } return -1; } Working demo: http://jsfiddle.net/jfriend00/mt8WG/ FYI, here's a somewhat performance optimized version of this function: function findSubArrayIndex(master, sub) { var subLen = sub.length, subFirst, m, mlen; if (subLen > 1) { subFirst = sub[0]; for (m = 0, mlen = master.length - subLen + 1; m < mlen; m++) { if (master[m] === subFirst) { for (var s = 1; s < subLen; s++) { if (master[m + s] !== sub[s]) { break; } else if (s === subLen - 1) { return m; } } } } } else if (subLen === 1) { subFirst = sub[0]; for (m = 0, mlen = master.length; m < mlen; m++) { if (master[m] === subFirst) { return m; } } } return -1; } Working demo: http://jsfiddle.net/jfriend00/CGPtX/
function index (a, b) { var as = new String(a), bs = new String(b), matchIndex = as.indexOf(bs); if (matchIndex === -1) { return -1; } else if (matchIndex === 0) { return 0; } return as.substring(0, matchIndex + 1).match(/,/g).length; } console.log(index([5,9,3,6,8], [3, 6]));
Try this - You loop through both arrays and compare each element: var arr1 = [5,9,3,6,8]; var arr2 = [3,6]; findArrayInArray = function(arr1, arr2) { for(var i=0; i<arr1.length; i++) { for(var j=0; j<arr2.length; j++){ if(arr1[i] === arr2[j]){ return i; } } } return false; } findArrayInArray(arr1, arr2);