Removing the elements from one multidimensional array from another multidimensional array - javascript

I'm finding it difficult getting my head around what I think is a pretty simple task. My brain is just fried at the moment and I have a deadline. :(
I need to take all the element arrays from one multidimensional array and remove them from another multidimensional array.
Arr1 = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
Arr2 = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
So in this instance I want to take all the element arrays from Arr2 and remove them from Arr1 so that afterward Arr1 would look like this:
Arr1 = [["Dick", "29"], ["Sally", "11"]];
Does that make sense?
EDITx2: Wait, no, ignore that, I was being stupid.

Assuming you always have two elements in the array, and a "unique" element is defined as a combination of the name and the number, you can do something like this:
function(array1, array2) {
var seen = {};
var returnedArray = [];
for(var i = 0; i < array2.length; i++) {
var elements = array2[i];
seen[elements[0] + elements[1]] = true;
//an alternative to the above is to do
//seen[JSON.stringify(elements)] = true;
}
for(var i = 0; i < array1.length; i++) {
var elements = array1[i];
if(!seen[elements[0] + elements[1]]) {
returnedArray.push(elements);
}
//an alternative to the above is to do
//if(!seen[JSON.stringify(elements)]) {
// ...
//}
//
//if you took the alternate approach in the first loop
}
return returnedArray;
}

Since it's all strings you could get creative with string methods and chaining. Probably not the best performance and a bit tricky, but it works:
var arr = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
var remove = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
var result = arr
.join('|')
.replace(RegExp(remove.join('|'),'g'),'')
.match(/[^|]+/g)
.map(function(s){ return s.split(',') });
console.log(result); //=> [["Dick","29"],["Sally","11"]]
You could even try using JSON. I wouldn't recommend this for production in any case, just for fun.
Demo: http://jsbin.com/obokuy/1/edit

If you need to put together something quick, then use a nested loop to walk through the elements of Arr2 for each element in Arr1 and do a comparison on each. You can look at the answers to this question for a hint on comparing the inner arrays:
How to check if two arrays are equal with JavaScript?

Related

How does one consolidate multi-dimensional arrays?

I am trying to get one array with a complete string:
['...']
Given:
Array1 = ['...', ['...'], ['...', 2, 'x']]
This should handle any size array*
Define a function, zooInventory, that accepts a multi-dimensional array of
animal facts.
zooInventory should return a new, flat array. Each element in the new array
should be a sentence about each of the animals in the zoo.
What I have currently:
const zooInventory = array => {
let finalArray = [];
for (let i = 0; i < array.length; i++) {
let currentElement = array[i];
if (!(Array.isArray(currentElement))) {
finalArray.push(currentElement);
} else {
zooInventory(currentElement);
// I thought I could push the currentElement back to beginning to handle additional arrays
}
}
return finalArray;
}
Where my heads at:
I thought I could get away with having it push(...array) in the else statement.
My batman belt contains beginner methods... slice, splice, spread.
What method would be best practice?
Simply use the .flat() method as shown in the snippet below.
More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
let arrayOne = ['...', ['...'], ['...', 2, 'x']];
console.log(arrayOne.flat());

How to get unique values from two 2D arrays in JavaScript

I am trying to get unique values from two arrays which looks like that:
array[{A,B,C},{C,D,E},{1,3,2},....]
both looks the same.
I tried to add them using concat and the get unique values from looping.
So I ended up with this:
function uniqueValues() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("arr1");
const array1 = srcSheet.getRange(1, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
var srcSheet1 = ss.getSheetByName("arr2");
const array2 = srcSheet1.getRange(1, 1, srcSheet1.getLastRow(), srcSheet1.getLastColumn()).getValues();
var dodaj = array1.concat(array2);
for (var i=0; i<dodaj.length; i++) {
var listI = dodaj[i];
loopJ: for (var j=0; j<dodaj.length; j++) {
var listJ = dodaj[j];
if (listI === listJ) continue;
for (var k=listJ.length; k>=0; k--) {
if (listJ[k] !== listI[k]) continue loopJ;
}
dodaj.splice(j, 1);
}
}
var result = ss.getSheetByName("test").getRange(2, 5, dodaj.length, 3).setValues(dodaj);
//Logger.log(dodaj);
}
It was working well when array looked like this array[{A,B},{C,D}] but with three elements it started to return duplicates as well... I have no idea what can be wrong.
If I understand you correctly, you want to retrieve the unique rows from the values in arr1 and arr2. That is to say, you want to remove duplicate inner arrays from dodaj.
After using concat to merge the two arrays, you could do the following:
Use JSON.stringify() to transform each inner array to a string, in order to compare them without iterating through them.
Use the Set constructor and the spread syntax in order to remove the duplicate strings (see this answer).
Transform the strings back to arrays with JSON.parse().
Code snippet:
var dodaj = array1.concat(array2);
dodaj = [...new Set(dodaj.map(JSON.stringify))].map(JSON.parse);
var result = ss.getSheetByName("test").getRange(2, 5, dodaj.length, dodaj[0].length).setValues(dodaj);

jquery json .. sort data array custom list .. how?

I want sort values ​​by array Another
for example
var objName = [{id:1, name:"one"},{id:2, name:"two"}, {id:3, name:"three"}];
var sortById = [1,3,2];
I want this output in that order
1 one
3 three
2 two
Stuff objName elements into a hash (i.e. object) indexed by id, then map the sortById array onto the hash values.
Exact code left as an exercise for the reader.
sorted=new Array()
for(var id_index=0;id_index<sortById.length;id_index++)
{
for(var obj_index=0;obj_index<objName.length;obj_index++){
if (objName[obj_index].id===sortById[id_index]) sorted.push(objName[obj_index])
}
}
//now sorted is the new sorted array. if you want to overwrite the original object:
objName=sorted;
Supposing that the length of both arrays are the same you can first create a hash:
var objName = [{id:1, name:"one"},{id:2, name:"two"}, {id:3, name:"three"}];
var myHash = {};
for(var i = 0; i<objName.length;i++){
myHash[objName[i].id] = objName[i];
}
Once you have this hash, you can loop over your keys array and get the values out:
var sortById = [1,3,2];
var sortedArray = [];
for(var i = 0; i<sortById.length;i++){
sortedArray.push(myHash[sortById[i]]);
}
Something clear and readable (subjective, probably not for everyone):
var result = [];
sortById.forEach(function(id) {
result = result.concat(objName.filter(function(i) {
return i.id == id;
}));
});
JSFiddle: http://jsfiddle.net/RLH6F/
Implemented just for fun.
Warning: O(n^2)
PS: I agree it would be better just give the recipe without the code, but as soon as there are already community members provided the copy-paste solutionы I decided to provide at least a nice looking one.

define associate array without value

I have a very large hard coded index array that I would like to easily convert to an associative array so lookups are much quicker.
var arr = ["a", "b", "c"];
right now I am looping through arr and comparing it's values to a value to see if there is a match. Now that I have hundreds of elements it's getting rather slow and it would be faster to have an associative array.
It seems I can't just do
var arr = {"a", "b", "c"};
I can't really add a value since it is too slow.
Sure I could copy the elements to an associate array or sort the array and do a binary search but it would be much easier to just able to assign a default value to the array elements and use the syntax above.
I guess this is not possible though?
var mapLookup = arr.reduce(function (accumalator, value) {
accumalator[value] = true;
return accumalator;
}, {});
Why not:
var arr = {"a":1, "b":1, "c":1};
Converting arrays to associative arrays seems to be the easiest and very fast:
var arr = ["a", "b", "c"];
var arrA = {}; for(var i = 0; i < arr.length; i++) arrA[arr[i]] = 0;
then just use key in arrA for O(1) lookup. (it would be easier to have the ability not have to explicitly supply a value to a key but....)
Essentially
if (key in arrA) ...
replaces
for(var i = 0; i < arr.length; i++) if (key == arr[i]) ...
which essentially is O(n) vs O(n^2) when uses inside a loop.
Most modern browsers support Array.indexOf(). This will return -1 if your search bears no results.
Are you actually having speed issues, or are you just pre-optimizing? The container you should be using is an array. You have an array of elements - they don't associate with any other values, so why put them in a map container?
Also, it sounds like you want a set, where you have a unique set of elements.

I iterate a loop within another loop, based on the same array, what's the best way to ignore duplicates?

I want to save all combinations of an array. So for
[a, b, c] I want to save
[ab, ac, ba, bc, ca, cb]
I currently use this method:
for (coordinate in coordinates){
for (coordinate2 in coordinates){
if (coordinate != coordinate2){
newposts.push([fbposts[fbpost].id, coordinates[coordinate], coordinates[coordinate2]]);
}
}
}
but it generates a bunch of duplicates. What's the smoothest way to solve this?
You could use a modified bubble sort algorithm:
var result = [],
arr = 'abc'.split('');
// begin the bubble sort loop
for(var i=0,l=arr.length;i<l-1;i++)
for(var j=i+1;j<l;j++)
{
result.push(arr[i]+arr[j]);
result.push(arr[j]+arr[i]);
}
console.log(result); //["ab", "ba", "ac", "ca", "bc", "cb"]
By looping over the array in this way, you do not even need to check if the result is a duplicate, because it doesn't generate any.
Btw, don't use the for..in synthax for looping over arrays because it may have unexpected results.
Add a check before adding to your new array either by custom function or perhaps
array.indexOf(...)
Custom function similar to how jQuery does it:
function inArray(needle, haystack) {
var length = haystack.length;
for(var i = 0; i < length; i++) {
if(haystack[i] == needle) return true;
}
return false;
}
So as you are building your new array of permutations/combinations (been 13+ years since my last stats class), perform a quick check and don't add if true, otherwise add. I believe if you perform an array merge it'll do similar so same performance.
You could take advantage of the fact that you can define a property only once and have something like this:
$(function() {
var arr = ["a","b","c"];
var permutations ={};
$.each(arr, function(index1, val1)
{
$.each(arr, function(index2, val2)
{
permutations[val1+val2] = 0;
});
});
for(var prop in permutations)
{
//in prop you will have your elements: aa,ab...
}
});​
permutations would play the role of a dictionary in this case
The logic of generating the combinations is sub optimal as the run time is n square - see this questions for algorithms of generating combinations of k elements out of an n elements array

Categories

Resources