Removing arrays from other arrays [duplicate] - javascript

This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 8 years ago.
Assume that I have this array:
a = [
[2823832908, 10071920],
[5384625228, 10924221],
[8488934028, 313411415],
[2823828588, 10071580],
[5224682868, 14919881],
[8155986228, 560217208],
[3458951628, 10071570],
[6382592388, 25064430],
[5021452668, 10924221],
[8827673748, 59397160],
[8647215588, 26343621]
]
and this array:
b = [
[8488934028, 313411415],
[8647215588, 26343621]
]
How can I get a new array that contains the values in array a that are not in array b, or how can I remove the values in array b from array a?

Create an empty result array.
Iterate over a, select its current element i.e. [2823832908, 10071920]
Compare current element for equality against each element of b , to compare equality
you can use JSON.stringify or .join to create string representation of arrays.
If the current element does not match any element of b, appent it to result array.
Repeat.
a = [
[2823832908, 10071920],
[5384625228, 10924221],
[8488934028, 313411415],
[2823828588, 10071580],
[5224682868, 14919881],
[8155986228, 560217208],
[3458951628, 10071570],
[6382592388, 25064430],
[5021452668, 10924221],
[8827673748, 59397160],
[8647215588, 26343621]
];
b = [
[8488934028, 313411415],
[8647215588, 26343621]
];
var result = [];
a.forEach(
function(elem,idx,arr)
{
var sig = JSON.stringify(elem);
var match = false;
for(var i=0;i<b.length;i++)
{
if(sig == JSON.stringify(b[i]))
{
match = true;
break;
}
}
if(match === false)
{
result.push(elem);
}
}
);
console.log(result);
demo : http://jsfiddle.net/Ag39M/4/

This is a bit tricky, principally because two arrays are not equal in Javascript, even if they have exactly the same keys.
You have to compare them manually, for example with this function by Tim Down.
You will then have to loop through the values in first array and compare them to every value in the second array.
The code might look like this:
var filtered = [];
// loop through every element in a
a.forEach(function(elA) {
// loop through every element in b
// if the elA is identical to any elB, some will immediately return true
// if elA is not identical to any elB, it will return false
var found = a.some(function(elB) {
return arraysIdentical(elA, elB);
});
// if we didn't find any equal ones, we'll add elA to the filtered array
if (!found) {
filtered.push(elA);
}
});
Note that this relies upon Array#forEach and Array#some. If you need to support older browsers, you'll need to shim them, with the polyfill code in those links.

Here's an implementation using undescore.js.
function diff(a1, a2) {
return _.filter(a1, function(e1) {
return !_.some(a2, function(e2) {
return _.isEqual(e1, e2);
});
});
}
Example:
var a = [ [ 1, 2 ], [ 3, 4 ], [ 5, 6, 7 ], [ 8 ], [ 9 ] ];
var b = [ [ 1, 2 ], [ 8 ], [ 9 ] ];
console.log(diff(a, b));
// [ [ 3, 4 ], [ 5, 6, 7 ] ]

function arra_diff(a, b)
{
var arr=[], diff=[];
for(var i=0;i<a.length;i++)
arr[a[i]]=true;
for(var i=0;i<b.length;i++)
if(arr[b[i]]) delete arr[b[i]];
else arr[b[i]]=true;
for(var k in arr)
diff.push(k);
return diff;
}
or
function arra_diff(d, c) { /* d=a,c=b */
for (var b = [], e = [], a = 0; a < d.length; a++) {
b[d[a]] = !0;
}
for (a = 0; a < c.length; a++) {
b[c[a]] ? delete b[c[a]] : b[c[a]] = !0;
}
for (var f in b) {
e.push(f);
}
return e;
};

Related

Javascript - Adding multiple values to keys

I am trying to find the places of each letter in a sentence by using "dictionaries". The problem is I want to find all the places that each letter is and not only the last one. I am very new to JavaScript and couldn't figure out the way to do it.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g,'');
var dict = {};
for (var i=0; i < stringArgument.length; i++ )
if (!stringArgument[i] in dict){
dict[stringArgument[i]] = [];
}else{
dict[stringArgument[i]] = [i+1]
}
return dict
}
var a = letters('Lost time is never found again.');
console.log(a);
naturally gives this output:
{ L: [ 1 ], o: [ 17 ], s: [ 10 ], t: [ 5 ]...
but it should give this:
{ L: [ 1 ], o: [ 2, 17 ], s: [ 3, 10 ], t: [ 4, 5 ]...
Also each letter is saved to the dictionary at the same order they appear in the sentence, how can I order the letters alphabetically?
What you need is a function that gets the positions of a character in a given string.
Try this:
function findAllPositions(char, content) {
var result = [];
let index = content.indexOf(char);
while(index !== -1) {
result.push(index);
index = content.indexOf(char, index + 1);
}
return result;
}
findAllPositions('o', 'Lost time is never found again.'); // Result =  [1, 20]
Using this we can update the letter function as follows:
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, '');
var dict = {};
for (const char of stringArgument) {
dict[char] = findAllPositions(char, stringArgument)
}
return dict;
}
letters('is again.')
/*
{
"i": [0, 5],
"s": [1],
"a": [2, 4],
"g": [3],
"n": [6],
".": [7]
}
*/
You need to have
parantheses for the check
if (!(stringArgument[i] in dict)) {
create an array if the above is true
push the postion to the array
For getting a sorted output, you could take the entries of the object, apply a sorting by taking the key and show the result in order.
Object have an insertation oder for not positive 32 bit numbers (like indixes) or symbols. The index like numbers are sorted by value and appears first in the object.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, '');
var dict = {};
for (var i = 0; i < stringArgument.length; i++) {
if (!(stringArgument[i] in dict)) {
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i + 1);
}
return dict;
}
var a = letters('Lost time is never found again.');
Object
.entries(a)
.sort(([a], [b]) => a.localeCompare(b))
.forEach(([key, positions]) => console.log(key, ...positions));
console.log(a);
First, for any item, if it is not in an empty array:
var notInDict = !(stringArgument[i] in dict);
If not in dict, then initialize an empty array and push the item in it using
dict[stringArgument[i]].push(i + 1);
Try this.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, "");
var dict = {};
for (var i = 0; i < stringArgument.length; i++) {
var notInDict = !(stringArgument[i] in dict);
if (notInDict) {
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i + 1);
}
return dict;
}
var a = letters("Lost time is never found again.");
console.log(a);
you are assigning a new array at each iteration
dict[stringArgument[i]] = [i+1]
what you need to do is push the new position to existing array.
dict[stringArgument[i]].push(i+1)
also, remove the else block
function letters(stringArgument) {
stringArgument = stringArgument.toLowerCase().replace(/ /g,'');
var dict = {};
for (var i=0; i < stringArgument.length; i++ ){
if (!dict.hasOwnProperty(stringArgument[i])){
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i+1);
}
//sorting
var letters = Object.keys(dict); //returns a array
letters.sort();
var sortedDic = {};
for(var i in letters) {
sortedDic[letters[i]] = dict[letters[i]];
}
return sortedDic;
}
var a = letters('Lost time is never found again.');
console.log(a);
for the first part you can also do that:
let sentence = 'Lost time is never found again.'
let tabLetters = [...sentence.replace(/ /g,'')].reduce((a,c,i)=>
{
if (!a[c]) a[c] = [i+1]
else a[c].push(i+1)
return a
},{})
document.write(JSON.stringify(tabLetters))

Javascript stop push when unique value occur

I populate a 2d array with a while loop, but I need to stop the push when the 1st column contains 3 different unique value.
the start is something like this
var maxunique;
var i = 0;
while (countunique(arr) != maxunique) {
// my code that push data into array
arr[i].push(RandomNumber(1,8));
arr[i].push(i+1);
i++;
}
function countunique(arr)
{
// function here
}
function RandomNumber(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
This return that value
arr: [ [ 4, 1 ],
[ 7, 2 ],
[ 5, 3 ],
[ 5, 4 ],
[ 3, 5 ],
[ 1, 6 ],
[ 7, 7 ],
[ 8, 8 ],
[ 5, 9 ],
[ 5, 10 ] ]
Whell the idea about the expected result is
arr: [ [ 4, 1 ],
[ 7, 2 ],
[ 5, 3 ] ]
you can see that the push is interrupted after the first 5, that is the 3 unique value in array
I don't know how to do it, and I don't know if is better do to with a while or a for loop.
Any Idea?
In the loop where you are populating the 2D array, have the array sent to a check function that determines if 3 unique elements are present as the first elements in the individual array. Here is the code for check function, it returns true if 3 unique elements are not yet present, once it finds 3 unique elements it returns false.
var a = []; //;
var i = 0;
while (check(a)) {
a[i]=[];
a[i].push(RandomNumber(1, 42));
a[i].push(i + 1);
i++;
}
function RandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function check(arr) {
var length = arr.length;
var tmp = [];
for (var j = 0; j < length; j++) {
if (tmp.indexOf(arr[j][0]) === -1) {
tmp.push(arr[j][0]);
}
if (tmp.length === 3) {
return false;
}
}
return true;
}
console.log('test: ', a);
console.log('check: ', check(a));
You could use one object to store each first number as property and check in each iteration of while loop if any value in that object is equal 3. If it is you can break from loop. I used random number for first number.
var ar = [];
var obj = {}
while (true) {
var firstNum = parseInt(Math.random() * 5) + 1;
ar.push([firstNum, 1]);
obj[firstNum] = (obj[firstNum] || 0) + 1;
var stop = Object.keys(obj).find(function(e) {
return obj[e] == 3;
});
if (stop) break;
}
console.log(obj);
console.log(ar);
You could implement a function which stores the number of the first column as a property in a object and increments a counter if that number does not exist in that object.If the counter is equal to 3 then there are 3 unique elements,then stop the array push and break out of the loop.
Here is an example code.
var arr = ['-15, 1',
'-15, 2' ,
'2,3' ,
'2, 4' ,
'2, 5',
'77, 6','22,3' ];
function unique(array) {
var arr = [],x,y,obj = {},count = 0,arr1;
for (i = 0; i < array.length ; i++) {
arr1 = array[i].split(',');
x = arr1[0] * 1;
y = arr1[1] * 1;
if (count === 3) {
break;
}
array.push([x,y]);
if (!obj[x]) {
obj[x] = 1;
count++;
}
}
}
This implements a real push:
var yourarray={
arr:[],
push:function(obj){
for(a=0;a<this.obj.length){
let count=0;
for(i=0;i<this.arr.length;i++){
if(obj[a]!=this.arr[i][a]){
count++;
if(count==3){
break;
}
}
}
}
this.arr.push(obj);
};
};
Now you can do:
yourarray.push([0,1,2]);
And access it like:
alert(yourarray.arr);
However, accessing yourarray directly isnt possible anymore

recursively putting array elements in their own array

I'm trying to create a function that puts each array element in its own array, recursively.
I think my base case is correct, but my recursive call doesn't appear to be working. any insight?
function ownList(arr){
if (arr.length === 1) {
arr[0] = [arr[0]];
return;
} else {
return arr[0].concat(ownList(arr.slice(1)));
}
}
var arr = [1,2,3]
console.log(ownList(arr))// returns []
//should return [[1],[2],[3]]
Here I'm trying to put each pair in it's own list (recursive only). This code below is correct (update)
function ownListPair(arr){
if (arr.length === 0)
return arr;
else if(arr.length === 1)
return [[arr[0], 0]];
else
return [[arr[0], arr[1]]].concat(ownListPair(arr.slice(2)));
}
// var arr = [3,6,8,1,5]
var arr = [2,7,8,3,1,4]
//returns [ [ 2, 7 ], [ 8, 3 ], [ 1, 4 ]]
console.log(ownListPair(arr))
I prefer this solution for several reasons:
function ownList(a) {
return a.length == 0
? []
: [[a[0]]].concat(ownList(a.slice(1)))
}
It's shorter and more concise
It works for empty arrays as well
The actual wrapping happens only once in the last line. Treating length == 1 separately -- as suggested by others -- is not necessary.
It would more appropriate to make a length of 0 be the null case. Then you just have to get the brackets right. The thing on the left side of the concat should be an array consisting of the array containing the first element.
function ownList(arr) {
return arr.length ? [[arr[0]]].concat(ownList(arr.slice(1))) : [];
}
Here's an alternative, take your pick:
function ownList(arr) {
return arr.length ? [[arr.shift()]] . concat(ownList(arr)) : [];
}
Using a bit of ES6 magic for readability:
function ownList([head, ...tail]) {
return head === undefined ? [] : [[head]] . concat(ownList(tail));
}
Here the [head, ...tail] is using parameter destructuring which pulls the argument apart into its first element (head) and an array of remaining ones (tail).
Instead of concat you could also use the array constructor:
function ownList([head, ...tail]) {
return head === undefined ? [] : Array([head], ...ownList(tail));
}
I think your basic assumption is wrong. What you need to do is check if each item in the array is an array, if not just add the item to the new array, if so have the function run itself on the array item.
That is recursion.
This code does that kind of recursion...
function ownList(arr)
{
var newArr = [];
var length = arr.length;
for (var i = 0; i < length; i++) {
if (typeof(arr[i]) === 'object') {
newArr.push(ownList(arr[i]));
continue;
}
newArr.push([arr[i]]);
}
return newArr;
}
var arr = [1, 2, 3];
console.log(ownList(arr));
Would something like this work:
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]],
result = [];
function flatten(input){
input.forEach(function(el){
if(Array.isArray(el)){
flatten(el)
}else{
result.push([el]);
}
});
}
flatten(arr);
console.log(JSON.stringify(result));
//[[1],[2],[3],["a"],["b"],["c"],["str"]]
JSBIN
Edit:
var result = [];
function flatten(input){
if (input.length === 0){
console.log( "result", result ); //[[1],[2],[3],["a"],["b"],["c"],["str"]]
return;
}
//if zeroth el of input !array, push to result
if (!Array.isArray(input[0])){
result.push(input.splice(0, 1));
flatten(input);
}else{
flatten(input[0]); //else, give input[0] back to flatten
}
}
window.onload = function(){
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]];
flatten(arr);
}
JSBIN
After struggling through this today, turns out that this works :)
function ownList(arr){
//base case:
if (arr.length === 1) {
return [arr];
}
//recurse
//have to do two brackets here --> (arr.slice(0,1)) since length > 1
return [arr.slice(0,1)].concat(ownList(arr.slice(1)));
}
var arr = [1,2,3]
console.log(ownList(arr))// returns [[1],[2],[3]]

Check for duplicates in an array

I have a function that will check a serialized form data if there are duplicates values in it.
s = $('#multiselectForm').serialize();
var x = [];
var y = [];
x = s.split("&");
for (var i = x.length - 1; i >= 0; i--) {
y.push(x[i].split("="));
};
var c = 0;
var e = 0;
for (var i = y.length - 1; i >= 0; i--) {
if (y[i][1] == y[c][1]) {
e++;
$('.duplicateAlert').show();
} else {
$('.duplicateAlert').hide();
};
c++;
};
Basically, what it does is split the string produced by the serialize() function and push the data into arrays.
The array I'm trying to parse looks like this:
Array [
Array [
0: 'my_field1',
1: 'val1'
],
Array [
0: 'my_field2'
1: 'val2'
],
Array [
0: 'my_field3'
1: 'val1'
]
]
Are there any better ways to do the same task? Maybe even shorter?
Create an empty array to hold the matches
Loop through the array. On each iteration...
Loop through the matches array and check if an item with the same value exists. If it does, set the matched flag.
Check if the matched flag has been set
if so, alert the user
if not add the item to matches.
var array = [
[ 'my_field1', 'val1' ],
[ 'my_field2', 'val2' ],
[ 'my_field3', 'val1' ],
[ 'my_field4', 'val2' ],
[ 'my_field5', 'val3' ]
], matches = [], match = false;
for(var i = 0, j = array.length; i < j; i++) {
match = false;
for(var k = 0, l = matches.length; k < l; k++) {
if(matches[k][1] == array[i][1]) {
match = true;
}
}
if(match) alert('Duplicate!');
else matches.push(array[i]);
}
If you have serialised data in the typical format like:
var data = 'foo=foo&bar=bar%26bar&blah=foo';
then you can check it for duplicates by getting the values between = and & and looking for dupes:
var seen = {};
var hasDupes = (data.match(/=[^&]+/g) || []).some(function(v){
return v in seen || (seen[v] = true) && false;
});
console.log(hasDupes); // true
The idea behind:
data.match(/=[^&]+/g) || []
is that match can return null if no matches are found, so if that happens the expression returns an empty array and the following call to some is called on the empty array (and returns false) rather than null, and hence doesn't throw the error that it would otherwise.
However, I still think it would be more efficient to check the form control values directly before serialising, rather than serialising the form then checking the result.
You can do that with a function like:
function checkDupValues(form) {
var value,
seen = {},
controls = form.elements;
for (var i=0, iLen=controls.length; i<iLen; i++) {
// Might want to check type of control here and ignore buttons, etc.
value = controls[i].value;
// Ignore empty controls?
if (value != '' && value in seen) {
// have a duplicate value that is not ''
alert('have dupes');
} else {
seen[value] = true;
}
}
}
Try this although its not much shorter:
var array = [
[
'my_field1',
'val1'
],
[
'my_field2',
'val2'
],
[
'my_field3',
'val1'
]
]
var originals = [];
var duplicates = [];
for (a in array) {
if (originals.indexOf(array[a][1] == -1)) {
originals.push(array[a][1])
} else {
duplicates.push(array[a])
}
}
alert('duplicates: ' + duplicates.join(', '));

Binomial sub arrays

I have an A array with n length.
I want to take all possible k (0
for example, if i have A's length is five:
[1,2,3,4,5]
and if k = 3, algorithm must give me B array.
[1,2,3 ]
[1,2, 4 ]
[1,2, 5]
[1, 3,4 ]
[1, 3, 5]
[1, 4,5]
[ 2,3,4 ]
[ 2,3, 5]
[ 2, 4,5]
[ 3,4,5]
Length of B would be equal to n!/k!(n-k)! ('!' means factorial, Newtons method)
I'm using javascript, so in my tags i included it, but it's just algorithm, not necessary written in javascript.
You could do this via a filter method.
In your example you want to receive all permutations of an array, taking a specific number of elements of that array.
You can easily do that in an iterative manner.
Start by taking all permutations of n - 1 elements of an array:
// return all (n - 1) element permutations of an array
var permutations = function(arr) {
return arr.reduce(function(re, value, i) {
// add an array for each element in the original array
return re.concat([arr.filter(function(v, index) {
// drop each element with the same index
return index !== i
})])
}, [])
}
Now permutations([1,2,3]) would return [[1,2], [1,3], [2,3]]
That's always a disjoint set suppose you're having only unique values in the source array.
To receive all 3-element arrays of a 5-element array, you would first calculate the list of 4-element arrays and transform each of them to a 3-element array.
permutations([1,2,3,4]).map(permutations)
=> [[1,2,3] => [[[1,2], [1,3], [2,3]]
,[1,2,4] ,[[1,2], [1,4], [2,4]]
,[1,3,4] ,[[1,3], [1,4], [3,4]]
,[2,3,4] ,[[2,3], [2,4], [3,4]]
] ]
Obviously the problem here is that there are doubles.
That can be solved by dropping all non-unique values.
var unique = function(arr) {
var s = arr.map(function(v) { return "" + v })
return arr.filter(function(v, i) { return s.indexOf("" + v) == i })
}
Packing it all into one function could be done like this:
var permutationsWithLength = function(arr, length) {
var re = [arr]
for (var i = arr.length; i >= length; i--) {
re = re.reduce(function(tmp, perms) {
return unique(temp.concat(permutations(perms)))
}, [])
}
return re
}
I admit that this may not be the fastest approach, especially regarding the unique function, but it's a very generic one and will work for the problem you described even with larger arrays.
Hope it helps ;)
Below is the copy-paste from one of my projects. Don't know if it still works ;)
var choose = function choose_func(elems, len) {
var result = [];
for (var i=0; i<elems.length; i++) {
if (len == 1) {
result.push([elems[i]]);
} else {
var remainingItems = choose_func(elems.slice(i+1, elems.length), len - 1);
for (var j=0; j<remainingItems.length; j++)
result.push([elems[i]].concat(remainingItems[j]));
}
}
return result;
};
var result = choose([1,2,3,4,5], 3)
/*result = [[1,2,3],[1,2,4],[1,2,5],[1,3,4],[1,3,5],
[1,4,5],[2,3,4],[2,3,5],[2,4,5],[3,4,5]] */

Categories