Locate an item in a multidimensional array by using a single index - javascript

I have this multidimensional array:
points= [['1','2','3'], ['4','5','6'] ]
and i have this array of points needed for a check in the above array;
new_points = [ 'a','b', 'c', 'd', 'e', 'f']
So a goes to 1 (0,0) , b to 2 (0,1) etc so points becomes;
points= [['a','b','c'], ['d','e','f'] ]
the multi-dimension array will always be 3 by 3, 4 by 4 etc.

Use two .map() and in nested function get index of relevant item of new_points based on map index.
var points= [['1','2','3'], ['4','5','6']];
var new_points = [ 'a','b', 'c', 'd', 'e', 'f'];
var newArr = points.map(function(item, i){
return item.map(function(val, j){
return new_points[(item.length*i)+j];
});
});
console.log(newArr);

If points is 2 dimensional but the nested array can be of variable length then you can reduce points using a counter to help get the item from new_points:
const points = [[1], [2, 3]];
const new_points = ['a', 'b', 'c'];
const createNewPoints = (points, new_points) =>
points.reduce(
([result, counter], items) => [
result.concat([
items.map((_, i) => new_points[i + counter]),
]),
counter + items.length,
],
[[], 0],
)[0];
console.log(createNewPoints(points, new_points));

You could shift each element of new_points by mapping the original array structure.
var points = [['1', '2', '3'], ['4', '5', '6']],
new_points = ['a', 'b', 'c', 'd', 'e', 'f'];
points = points.map(a => a.map(Array.prototype.shift, new_points));
console.log(points);

Related

Search for string duplicate in multidimensional array

I have multidimensional array with strings:
const arr = [['a', 'b'], ['c', 'd'], ['d', 'a']]
How can i log to console all values that occur in all nested arrays more than 1 time? (For this example function should console.log 'a' and 'd').
Thanks for the help
You first flat the arr.Then remove duplicates from it using Set. And loop through it then compare lastIndexOf and indexOf
const arr = [['a', 'b'], ['c', 'd'], ['d', 'a']]
let flat = arr.toString().split(',');
[... new Set(flat)].forEach(a => {
if(flat.indexOf(a) !== flat.lastIndexOf(a)) console.log(a)
})
let findDupesInMDArray = (arr) => {
// flatten the array
const flat = arr.flat();
// filter for dupes
return flat.filter((item, index) => flat.indexOf(item) != index)
}
let array = [['a', 'b'], ['c', 'd'], ['d', 'a']]
const dupes = findDupesInMDArray(array)
console.log(dupes)
Using spread syntax, Array#flat, Array#reduce, Array#filter and Array#map.
const arr = [['a', 'b'], ['c', 'd'], ['d', 'a']]
const res = Array.from(arr.flat().reduce((a,c)=>{
return a.set(c, (a.get(c)||0) + 1);
}, new Map()))
.filter(([,c])=> c > 1)
.map(([k])=>k);
console.log(res);
You could count the items by using a Map and get only the items with a count greater than one.
const
count = (m, a) => Array.isArray(a) ? a.reduce(count, m) : m.set(a, (m.get(a) || 0) + 1);
var array = [['a', 'b'], ['c', 'd'], ['d', 'a']],
result = Array
.from(array.reduce(count, new Map), ([k, v]) => v > 1 && k)
.filter(Boolean)
console.log(result);
Here's a more basic approach:
var array = [['a', 'b'], ['c', 'd'], ['d', 'a']]
var result = [];
for (var i in array){
for (var l in array[i]){
if(array[i][l]==='a'||array[i][l]==='d')
result.push(array[i][l])
}}
var unique = new Set(result) //creates a set with unique values
console.log(unique) //should log the set {'a','d'}
What we're doing here is
looping through the nested arrays twice
pushing the elements (if the element === 'a' or element ==='d') into a new array called result.
creating a new set with the unique values only

JavaScript/ES 6: Compare arrays length in an Object

I have an Object containing multiple arrays like this
someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd']
}
Is there any built-in method or property in JS/ES6 which returns the largest array or length of the largest array? Please suggest
You can use Array.prototype.reduce and check the value of accumulator with the array length.
Use Object.values() to get all the values of the array.
var someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd'],
array4:['a', 'b', 'c']
}
var maxLength = Object.values(someObj).reduce((a,e) => { return a > e.length ? a:e.length}, 0);
console.log(maxLength);
You can use Object.values to get all of the values for any object. Here's a neat oneshot which will return the longest list in combination with reduce:
const longestList = Object.values(someObj)
.reduce((longest, list) => list.length > longest.length ? list : longest)
Object.values: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
You can simply use a for loop and iterate through it comparing the length of the arrays.
var someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd']
}
var max=0;
for(x in someObj){
someObj[x].length > max ? max=someObj[x].length : max;
}
console.log(max);

Strange Array.slice behavior

Can anyone explain "slice" behavior?
var arr = ['a', 'b', 'c', 'd', 'e', 'f']
console.log(arr.slice(0, 4)); // [ 'a', 'b', 'c', 'd' ]
console.log(arr.slice(4, 4)); // []
Why the second array is empty? Should not it be ['e','f'] ?
If omit "end" param, the result as expected.
arr.slice(4, 4) will return the items beginning at index = 4 to index = 4; 4-4=0 so your array has got a length of 0
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
var arr = ['a', 'b', 'c', 'd', 'e', 'f']
console.log(arr.slice(0, 4)); // [ 'a', 'b', 'c', 'd' ]
console.log(arr.slice(4, 4)); // []
console.log(arr.slice(2, 4));
console.log(arr.slice(1, 2));
According to official docs it:
Returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.
Meaning that, you start at the index 4 and u end at that index, so literally you took no elements since the difference between start and end index is 0, so no elements are taken.

Reverse an array in an array reverses all arrays in the array [duplicate]

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 6 years ago.
var alph = ["a", "b", "c"];
var r = [];
for(var i = 0; i < 5; i += 1) {
r.push(alph);
}
r[0].reverse();
console.log(r);
/* Output
[ [ 'c', 'b', 'a' ],
[ 'c', 'b', 'a' ],
[ 'c', 'b', 'a' ],
[ 'c', 'b', 'a' ],
[ 'c', 'b', 'a' ] ]
*/
/* Expected output
[ [ 'c', 'b', 'a' ],
[ 'a', 'b', 'c' ],
[ 'a', 'b', 'c' ],
[ 'a', 'b', 'c' ],
[ 'a', 'b', 'c' ] ]
*/
There are arrays in an array. The first array should be reversed. I thought r[0].reverse() would do this, but instead this reverses all arrays.
Can someone explain why this happens ?
You are pushing the reference of the array, so updating one will make changes to the rest since it's all are referring single array. Instead push the copy of the original array for copying array use Array#slice method.
var alph = ["a", "b", "c"];
var r = [];
for (var i = 0; i < 5; i += 1) {
// push the exact copy of original array
r.push(alph.slice());
}
r[0].reverse();
console.log(r);
You're not creating an array of new arrays when you push onto r: you're pushing the same array onto r 5 times (it's being passed by reference, not by value). Therefore, any operation on r[0] is really updating alph, which causes all of the other references to be updated, too.
Well actually you can use slice method like #Pranav C Balan suggested but this will fail when the array is multidimensional. You need something like Array.prototype.clone() to secure the functionality. Lets do it.
Array.prototype.clone = function(){
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
var alph = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 ], 5 ],
cloned = [],
sliced = [];
for(var i = 0; i < 5; i += 1) {
cloned.push(alph.clone());
sliced.push(alph.slice());
}
cloned[0][4][2].reverse(); // only the array at index pos 0,4,2 gets reversed
sliced[0][4][2].reverse(); // all sub arrays at index 4,2 get reversed
console.log(JSON.stringify(cloned));
console.log(JSON.stringify(sliced));

How to get all unique elements in for an array of array but keep max count of duplicates

The question doesn't make much sense but not sure how to word it without an example. If someone can word it better, feel free to edit it.
Let's say I have an array of arrays such as this:
[ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ]
I would like the output to be:
['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e']
Not sure if there is an easy way to do this in javascript/jquery/underscore. One way I could think of is to look through each of these arrays and count up the number of times each element shows up and keep track of the maximum amount of times it shows up. Then I can recreate it. But that seems pretty slow considering that my arrays can be very large.
You need to:
Loop over each inner array and count the values
Store each value and its count (if higher than current count) in a counter variable
In the end, convert the value and counts into an array
Following code shows a rough outline of the process. Remember to replace .forEach and for..in with appropriate code:
var input = [['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e']],
inputCount = {};
input.forEach(function(inner) {
var innerCount = {};
inner.forEach(function(value) {
innerCount[value] = innerCount[value] ? innerCount[value] + 1 : 1;
});
var value;
for (value in innerCount) {
inputCount[value] = inputCount[value] ? Math.max(inputCount[value], innerCount[value]) : innerCount[value];
}
});
console.log(inputCount);
// Object {a: 2, b: 3, c: 1, d: 1, e: 1}
After messing around, I found a solution but not sure if I like it enough to use. I would probably use it if I can't think of another one.
I would use underscorejs countBy to get the count of all the elements.
var array = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var count = _.map(array, function(inner) {
return _.countBy(inner, function(element) {
return element;
});
});
var total = {};
_.each(_.uniq(_.flatten(array)), function(element) {
var max = _.max(count, function(countedElement) {
return countedElement[element];
});
total[element] = max[element];
});
console.log(total); // {a: 2, b: 3, c: 1, d: 1, e: 1}
Then I would recreate the array with that total.
Here is example of simple nested loop approach:
var input = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var countMap = {};
// iterate outer array
for (i=0; i < input.length; i++) {
// iterate inner array
for (j=0; j < input[i].length; j++) {
// increment map counter
var value = input[i][j];
if (countMap[input[i][j]] === undefined) {
countMap[value] = 1;
} else {
countMap[value]++;
}
}
}
console.log(countMap); // output such as {'a':2, 'b':4, 'c':1, 'd':1, 'e':1}
Not the most efficient solution but it should describe you the process:
var big = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
function map(arr){
var map = {}
for (var i=arr.length-1; i>-1; i--){
if(arr[i] in map) map[arr[i]]++;
else map[arr[i]] = 1;
}
return map;
}
function reduce(matrix){
var arrMap = {};
for (var i=matrix.length-1; i>-1; i--){
var arrRes = map(matrix[i]);
for (var key in arrRes){
if( !arrMap[key] || arrMap[key] < arrRes[key])
arrMap[key] = arrRes[key];
}
}
return arrMap;
}
function calc(matrix){
var res = [],
arrMap = reduce(matrix);
for (var key in arrMap){
while(arrMap[key] > 0 ){
res.push(key);
arrMap[key]--;
}
}
return res;
}
console.log(calc(big));
// Array [ "e", "b", "b", "b", "a", "a", "d", "c" ]

Categories