Finding missing array in array of arrays - javascript

I need to find a missing array in an "array of arrays". I started by finding this function below (on StackOverflow):
function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
var deselectedItem = [];
// loop through previous array
for(var j = 0; j < PreviousArrSize; j++) {
// look for same thing in new array
if (CurrentArray.indexOf(PreviousArray[j]) == -1)
deselectedItem.push(PreviousArray[j]);
}
return deselectedItem;
}
This works just fine if you did something like this:
oldarray = ["hi", "ho", "hey"];
newarray = ["hi", "hey"];
Using findDeselectedItem(newarray, oldarray) would return ["ho"].
However, my content looks like this:
oldarray = [["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
newarray = [["Olivia", 16, 0], ["James", 17, 1]];
How can I adapt the function above so that it returns the missing array containing 'Liam'.
Thanks

I would make a hash with the name as a key. That would make finding missing content trivial and very fast. You can then optimize the method by not rebuilding the hash every time, but only when it's really necessary.
var oldArray = [["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
var newArray = [["Olivia", 16, 0], ["James", 17, 1]];
function findDeselectedItems(oldArray, newArray)
{
var results = [];
var hash = {};
for (var i=0; i<newArray.length; i++) {
hash[newArray[i].join(',')] = true;
}
for (var i=0; i<oldArray.length; i++) {
if (!hash[oldArray[i].join(',')]) {
results.push(oldArray[i]);
}
}
return results;
}

The problem may be that indexOf uses strict equality. I.e. if an item in the 'previous' array isn't literally also in the 'current' array, it will report it to not be in there.
You will have to iterate over the values yourself (instead of using indexOf) and check if the array contains something that is 'the same as' (but not literally the same) the array.
I.e. if I didn't explain myself well enough take a look at this;
['bob'] == ['bob']; //false
//therefore
[['bob']].indexOf(['bob']); //-1

I hope that this helps you,
function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
var deselectedItem = [];
// loop through previous array
for(var j = 0; j < PreviousArrSize; j++) {
var checkArray = PreviousArrSize[j];
// loop through 2nd array to match both array
for(var i = 0; i < CurrentArrSize; i++) {
// look for same thing in new array
if (CurrentArray[i].indexOf(checkArray) == -1)
deselectedItem.push(CurrentArray[i]);
}
}
return deselectedItem;
}

#KarelG: nice and quick solution but should it not be var checkArray = PreviousArr[j]; instead of var checkArray = PreviousArrSize[j]; ?

function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
var deselectedItem = [];
var selectedIndices = [];
// loop through previous array
for(var j = 0; j < PreviousArrSize; j++) {
for(k=0; k < CurrentArrSize ; k++){
if (CurrentArray[k].toString() === PreviousArray[j].toString()){
selectedIndices.push(j);
break;
}
}
}
for(var l = 0; l < PreviousArrSize; l++){
if(selectedIndices.indexOf(l) === -1){
deselectedItem.push(PreviousArray[l]);
}
}
return deselectedItem;
}

I don't think you can use indexOf to compare two arrays. You need a deeper comparison. Although this code could be written another way, you could do this with an array comparison function and using Array.some() to filter through your elements. Here's an example and a fiddle;
// Credit http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript
// attach the .compare method to Array's prototype to call it on any array
Array.prototype.compare = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0; i < this.length; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].compare(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
var deselectedItem = [];
// loop through previous array
for (var j = 0; j < PreviousArrSize; j++) {
// look for same thing in new array
CurrentArray.some(function (a, idx) {
if(PreviousArray[j].compare(a) == false) {
deselectedItem.push(PreviousArray[j]);
return true;
}
});
}
return deselectedItem;
}
var oldarray =[["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
var newarray =[["Olivia", 16, 0], ["James", 17, 1]];
console.log(findDeselectedItem(newarray, oldarray));

Related

Compare Arrays with Javascript and build another Array

In Javascript:
I have an existing array like [4,5,6,10] - (These are 'repid').
I have an ajax response like [{"repid":5,"avgAmount":2.5},{"salesrepid":10,"avgAmount":3.0}].
I have to build a third array which will compare the 'repids' of the 2 arrays and build a third array so that it will place a '0' if the repids do not match or else the 'avgAmount' if they match.
So, in my case above, I would 'build' a third array:
[0, 2.5, 0, 3.0]
I've tried many variances of:
//need to assign the sales average values to the proper repid
for (var i = 0; i < repIds.length; i++) {
for (var j = 0; j < salesrepids.length; j++) {
if (repIds[i] == salesrepids[j]) {
salesvalues.push(key.avgAmount);
} else { salesvalues.push("0"); }
};
}
}
}
You need to address the correct keys of your objects. And also only add the 0 in case you don't find any matching entry:
var repIds = [4, 5, 6, 10];
var salesrepids = [{"repid": 5, "avgAmount": 2.5}, {"repid": 10, "avgAmount": 3.0}]
var salesvalues = [];
for (var i = 0; i < repIds.length; i++) {
var noMatch = true;
for (var j = 0; j < salesrepids.length; j++) {
if (repIds[i] === salesrepids[j]['repid']) {
salesvalues.push(salesrepids[j]['avgAmount']);
noMatch = false;
}
}
if (noMatch) {
salesvalues.push(0);
}
}
console.log(salesvalues);
You can do something like using map and find:
Loop through the first array -> Check if the id exists in the second array using find -> If yes, return it's avgAmount else return 0.
const ids = [4,5,6,10],
amounts = [{"repid":5,"avgAmount":2.5},{"repid":10,"avgAmount":3.0}];
const output = ids.map(i => {
const found = amounts.find(a => a.repid === i);
return found ? found.avgAmount : 0;
})
console.log(output)
May be like this:
var repids = [4,5,6,10];
var returns = [{"repid":5,"avgAmount":2.5},{"salesrepid":10,"avgAmount":3.0}];
var results = [];
for(var key in returns){
if(repids.includes(returns[key].repid)){
results.push(returns[key].repid);
results.push(returns[key].avgAmount);
}
if(repids.includes(returns[key].salesrepid)){
results.push(returns[key].salesrepid);
results.push(returns[key].avgAmount);
}
}
console.log(results);

Remove sub-array contains common elements

As the title, if the input is [[1,2], [3,4], [1,3], [5,6], [6,5]], output should be [[1,2,3,4], [5,6]].
It's wrong on the recursive part. In my code, after running it, I will get [[1,2,3],[1,3,4],[5,6]], which means I need once more merge, but I'm confused how to continue the code until no sub-array contains common element.
Here is my code
function need_merge_or_not(arr)
{
for (var i = 0; i <= arr.length-1; i++) {
for (var j = i+1; j <= arr.length-1; j++) {
var arr_new = arr[i].concat(arr[j]);
//remove deplicates
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
return true;
}
}
}
return false;
}
function merge(arr)
{
if (arr.length >= 2) {
for (var i = 0; i <= arr.length-1; i++) {
for (var j = i+1; j <= arr.length-1; j++) {
var arr_new = arr[i].concat(arr[j]);
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
arr.splice(arr.indexOf(arr[i]), 1);
arr.splice(arr.indexOf(arr[j]),1);
arr.push(arr_merge);
}
}
if (need_merge_or_not(arr)) {
return merge(arr);
}
}
}
return arr;
}
I figured it out. Here is the code:
function merge(arr){
var input = [];
for(var i = 0; i < arr.length; i++){
input.push(arr[i]);
}
if (arr.length >= 2) {
for (var i = 0; i < arr.length; i++) {
for (var j = i+1; j < arr.length; j++) {
var arr_new = arr[i].concat(arr[j]);
//remove duplicates
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
arr.splice(arr.indexOf(arr[i]), 1, arr_merge);
arr.splice(arr.indexOf(arr[j]),1);
j--;
}
}
}
if (!arraysEqual(input, arr)) {merge(arr)};
}
return arr;
//Input:[[1,2], [3,4], [1,3], [5,6], [6,5]]
//Output:[[1,2,3,4], [5,6]]
}
function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
You could use two hash tables, one for the items and their groups and on for the result sets.
Basically the algorithm generates for the same group an object with a property and an array, because it allowes to keep the object reference while assigning a new array.
The main part is iterating the outer array and then the inner arrays and check inside, if it is the first item, then check the hash table for existence and if not exists, generate a new object with a values property and an empty array as value. Also assign the actual object to sets with item as key.
In a next step, the hash table is checked again and if not exist, then assign the object of the first element.
To maintain only unique values, a check is made and if the item does not exist, the item is pushed to the hash table's values array.
Then a part to join arrays follows by checking if the object of the first item is not equal to object of the actual item. If so, it delete from sets the key from the actual items's values first item and concat the array of the actual items to the first item's object's values. Then the values object is assigned to the actual item's object.
Later the sets are maped to the result set with iterating the sets object and the values property is taken as value.
var array = [[1, 2], [3, 4], [1, 3], [5, 6], [6, 5]],
groups = {},
sets = {},
result;
array.forEach(function (a) {
a.forEach(function (b, i, bb) {
if (i === 0 && !groups[b]) {
groups[b] = { values: [] };
sets[b] = groups[b];
}
if (!groups[b]) {
groups[b] = groups[bb[0]];
}
if (groups[b].values.indexOf(b) === -1) {
groups[b].values.push(b);
}
if (groups[bb[0]] !== groups[b]) {
delete sets[groups[b].values[0]];
groups[bb[0]].values = groups[bb[0]].values.concat(groups[b].values);
groups[b].values = groups[bb[0]].values;
}
});
});
result = Object.keys(sets).map(function (k) {
return sets[k].values;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

JavaScript: How to throw away elements from one array, wchich are in another

I need function to return from arrays a and b, new array containing elements from b, which doesn't exist in array a.
For example:
a = [1,2,3,4]
b = [0,3,5]
return = [0, 5]
But elements are arrays eg:
a = [["a","fd","asfd"],["adsf","fdf","dsf"]
I tried a lot, but nothing happens. It's my code:
function clean(a, b){
var ln = a.toString()
for(var i = 0, length = b.length; i < length; i++) {
if(-1 !== ln.indexOf(String(b[i]))){
b.splice(ln.indexOf(b[i].toString()), 1)
}
}
return shorter;
}
It doesn't work.
Try this -
a = [1,2,3,4]
b = [0,3,5]
function clean(a, b){
var bb = b.slice(0); //making sure we are not changing the actual array
for(var i = 0; i < a.length; i++){
var index = bb.indexOf(a[i]);
if(index > -1){
bb.splice(index, 1);
}
}
return bb;
}
console.log(clean(a,b));
console.log(b);
Output :
[0, 5]
[0, 3, 5]
I tried the following, and it worked fine.
var b = [0,3,5];
var a = [1,2,3,4];
var ret = []
for(var i=0;i<b.length;i++){
var flag =0;
for(var j=0;j<a.length;j++){
if(a[j]===b[i]){
flag=1;
}
}
if(flag==0)
{
ret.push(b[i]);
}
}
console.log(ret);
// The question has two parts:
// The second in order of the question is:
// Make a flat list from a two-dimensional array:
aFlat = [].concat.apply([],a);
// The first is: Get all elements from b
// that are not contained in a (resp. aFlat):
c = b.filter( function(element) { return aFlat.indexOf(element) == -1 });

Inserting (splicing?) an Array into another Array without apply

Let's say we have two Arrays in JavaScript, [3,4,7] and [5,6].
Without sorting or using .apply, what is the best way to insert [5,6] into [3,4,7] at index 2 in order to achieve the resulting Array: [3,4,5,6,7]?
Don't know how you're defining "best way", but you can do this:
a.slice(0,2).concat(b,a.slice(2));
Unless you're saying you actually want to mutate the a Array, in which case you could do this:
var c = a.splice(2);
for (var i = 0; i < b.length + c.length; i++) {
a.push(i < b.length ? b[i] : c[i-b.length]);
}
This behavior of .splice() to split the Array in two parts may have issues in older IE that would need to be patched.
Or this would probably be better:
var c = b.concat(a.splice(2));
for (var i = 0; i < c.length; i++) {
a.push(c[i]);
}
Same caveat about .splice().
function splice(arrayOne, arrayTwo, index) {
var result = [];
for (var i = 0; i < arrayOne.length; i++) {
if (i == index) {
result = result.concat(arrayTwo);
}
result.push(arrayOne[i]);
}
return result;
}
Not really sure why you don't want to use the native methods, but here's a fairly naive solution with just loops:
function doInsert(index, items, arr) {
var insertLen = items.length,
current;
for (i = 0; i < insertLen; ++i) {
current = i + index;
arr[current + insertLen - 1] = arr[current];
arr[current] = items[i];
}
}
var arr = [3, 4, 7];
doInsert(2, [5, 6], arr);
console.log(arr);

how to compare two arrays of different length if you dont know the length of each one in javascript?

I am stuck in this. I got 2 arrays, I don't know the length of each one, they can be the same length or no, I don't know, but I need to create a new array with the numbers no common in just a (2, 10).
For this case:
var a = [2,4,10];
var b = [1,4];
var newArray = [];
if(a.length >= b.length ){
for(var i =0; i < a.length; i++){
for(var j =0; j < b.length; j++){
if(a[i] !=b [j]){
newArray.push(b);
}
}
}
}else{}
I don't know why my code never reach the first condition and I don't know what to do when b has more length than a.
It seems that you have a logic error in your code, if I am understanding your requirements correctly.
This code will put all elements that are in a that are not in b, into newArray.
var a = [2, 4, 10];
var b = [1, 4];
var newArray = [];
for (var i = 0; i < a.length; i++) {
// we want to know if a[i] is found in b
var match = false; // we haven't found it yet
for (var j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
// we have found a[i] in b, so we can stop searching
match = true;
break;
}
// if we never find a[i] in b, the for loop will simply end,
// and match will remain false
}
// add a[i] to newArray only if we didn't find a match.
if (!match) {
newArray.push(a[i]);
}
}
To clarify, if
a = [2, 4, 10];
b = [4, 3, 11, 12];
then newArray will be [2,10]
Try this
var a = [2,4,10];
var b = [1,4];
var nonCommonArray = [];
for(var i=0;i<a.length;i++){
if(!eleContainsInArray(b,a[i])){
nonCommonArray.push(a[i]);
}
}
function eleContainsInArray(arr,element){
if(arr != null && arr.length >0){
for(var i=0;i<arr.length;i++){
if(arr[i] == element)
return true;
}
}
return false;
}
I found this solution just using the filter() and include() methods, a very and short easy one.
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.
function compareArrays(a, b) {
return a.filter(e => b.includes(e));
}

Categories

Resources