I have an array like this:
[1, {a: 'b', c: 'd'}, {c: 'd', a: 'b'}, {e: 'f'}, 'b']
What I want to do is that I want to remove the duplicates from this array whether they are objects or not so that the final array could become this:
[1, {a: 'b', c: 'd'}, {e: 'f'}, 'b']
I have seen many solutions on the site but none works for my issue. How could I do it?
I tried this:
function uniq_fast(a) {
var seen = {};
var out = [];
var len = a.length;
var j = 0;
for(var i = 0; i < len; i++) {
var item = a[i];
if(seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
return out;
}
But this removed the third object aswell.
Thanks.
If you just want to compare references and not the object's contents, you can use:
arr.reduce(function(accumulator, element){
if (accumulator.indexOf(element) !== -1) return accumulator;
return accumulator.concat(element);
}, []);
Otherwise, you need to create a function that compares the object's contents, for example:
function objectsMatch(obj1, obj2) {
if (obj1 === obj2) return true;
for (var prop in obj1) {
if (!(prop in obj2) || obj1[prop] !== obj2[prop]) return false;
}
for (var prop in obj2) {
if (!(prop in obj1)) return false;
}
return true;
}
And then use something like:
arr.reduce(function(accumulator, element){
if (accumulator.some(function(otherElement){
return objectsMatch(element, otherElement);
})) return accumulator;
return accumulator.concat(element);
}, []);
This function will do it for you. It uses Object.keys() to cross reference the objects. If seen is populated with a known key and the known key content doubles that of the object in seen, delete property from object. Finally if object is empty delete the whole object from the array using splice. Note this solution only works if all input is like the provided sample. Else the function needs to be written recursively.
var abc = [1, {a: 'b', c: 'd'}, {c: 'd', a: 'b'}, {e: 'f'}, 'b'];
function uniq_fast(a) {
var seen = {};
var deleteObject = [];
var len = a.length;
for(var i = 0; i < len; i++) {
if (Object.prototype.toString.call(a[i]) === '[object Array]' || Object.prototype.toString.call(a[i]) === '[object Object]')
{
var test = Object.keys(a[i]);
var len2 = test.length;
for (var j = 0; j < len2; ++j)
{
if (seen[test[j]] && a[i][test[j]] === seen[test[j]])
{
delete a[i][test[j]];
}
else
{
seen[test[j]] = a[i][test[j]];
}
}
if (Object.keys(a[i]).length == 0)
{
deleteObject.push(i);
}
}
}
for (var i = 0; i < deleteObject.length; ++i)
{
a.splice(deleteObject[i], 1);
}
return a;
}
console.log(uniq_fast(abc));
Related
I've been trying to get an object output from an alphabetically sorted array.
For example, if I have arr = ['anger', 'apple', 'bowl', 'cat']
then I want my object to be like obj = { a: ['anger', 'apple'], b: ['bowl'], c:['cat']}
So far I have this, but it's not working properly.
const p4 = function (arr) {
let val = {};
const sortArr = arr.sort();
for (let i = 0; i < sortArr.length; i++) {
for (let j = i; j < sortArr.length; j++) {
if (sortArr[i].charAt(0) == sortArr[j].charAt(0)) {
val.sortArr[j].charAt(0) =sortArr[j] ;
}
}
return val;
}
};
You can use reduce:
let arr = ['anger', 'apple', 'bowl', 'cat']
const result = arr.reduce((a, b) => {
let c = b.charAt(0);
if (a[c]) {
a[c].push(b)
} else {
a[c] = [b];
}
return a;
}, {})
console.log(result)
In the code:
let val = {};
const sortArr = arr.sort();
sort sorts in place and returns the sorted array, so sortArr and arr both reference the same (sorted) array. You could just do:
arr.sort()
and use arr in the following instead of sortArr.
for (let i = 0; i < sortArr.length; i++) {
for (let j = i; j < sortArr.length; j++) {
There is no need to process the array twice. All you need to do is:
Iterate over each value in the array
Get the first letter of the value
If the val object doesn't have a property with that name, create it and assign an array to the value
Push the string into the val[char] array
E.g.
function arrToObj(arr) {
arr.sort();
let result = {};
for (let i=0, c; i<arr.length; i++) {
c = arr[i].substr(0,1);
if (!result[c]) {
result[c] = [];
}
result[c].push(arr[i]);
}
return result;
}
let arr = ['anger', 'apple', 'bowl', 'cat']
console.log(arrToObj(arr));
You can also do the same thing with reduce:
let arr = ['anger', 'apple', 'bowl', 'cat']
let obj = arr.sort().reduce((acc, v) => {
let c = v.substr(0,1);
if (!acc[c]) acc[c] = [];
acc[c].push(v);
return acc;
}, {});
console.log(obj);
Below is the code I unsuccessfully try to run in the console of chrome. Now the code of which looks like this and does not actually work.
Test.provide = Test.data = function arraaays() {
const c = [];
for (let i = 0; i < Math.max(a.length, b.length); i++) {
if (a[i] !== undefined) {
c.push(a[i]);
}
if (b[i] !== undefined) {
c.push(b[i]);
}
}
console.log(c);
}
The code itself should interact with two arrays that are in Test.data and create a new one of this type on their basis
a: ['a', 'b', 'c'] //first array
b: ['d', 'e'] //second array
c: ['a', 'd', 'b', 'e', 'c'] // new array
function arry(a, b) {
var c = [];
for (let i = 0; i < Math.max(a.length, b.length); i++) {
if (a[i] != undefined) {
c.push(a[i]);
}
if (b[i] != undefined) {
c.push(b[i]);
}
}
return c;
}
Test.provide = arry(Test.data.a, Test.data.b);
function pairElement(str) {
var arr = [['G','C'],['C','G'],['A','T'],['T','A']],b=[]
for(var k=0;k<arr.length;++k){
var res = arr.filter(function(v){
return v;
})[k][0]
var j=0;
while(j<str.length){
if(str[j]===res){
b.push(arr[k])
}
j++;
}
}
return b;
}
console.log(pairElement("ATCGA"));
I want pairing result in order of the argument passed to the main function. This code's result should be
[['A','T'],['T','A'],['C','G'],['G','C'],['A','T']] but i'm getting as [['G','C'],['C','G'],['A','T'],['A','T'],['T','A']]
Your inner and outer loops are flipped. The outer loop should iterate over the string, and the inner loop should iterate over the array.
function pairElement(str) {
var arr = [['G', 'C'], ['C', 'G'], ['A', 'T'], ['T', 'A']],
b = [];
for (var k = 0; k < str.length; k++) {
for (var j = 0; j < arr.length; j++) {
if (str[k] === arr[j][0]) {
b.push(arr[j]);
}
}
}
return b;
}
console.log(pairElement("ATCGA"));
Your code can also be simplified using an object instead of a 2D array, and with Array#map:
function pairElement(str) {
var pairs = { 'G': 'C', 'C': 'G', 'A': 'T', 'T': 'A' };
return str.split('').map(ch => [ch, pairs[ch]]);
}
console.log(pairElement("ATCGA"));
I've been trying to implement a function where given with two arrays,
array1's elements is used as conditions to filter out elements in array2.
For instance:
array1= [apple, grapes, oranges]
array2= [potato, pears, grapes, berries, apples, oranges]
After feeding into a function, array2 should have elements as such:
filter_twoArrays(array1,array2)
array2= [grapes, apples, oranges]
I've tried the following code, using for loops and array.splice(), but the problem I am seeing is that when I use the splice method, it seems that it changes the lengths of array2 in the for loop:
function filter_twoArrays(filter,result){
for(i=0; i< filter.length; i++){
for(j=0; j< result.length; j++){
if(filter[i] !== result[j]){
result.splice(j,1)
}
}
}
Any inputs will be greatly appreciated on how to refine the filter function
cheers!
You can use filter as follow
var array1 = ['apples', 'grapes', 'oranges', 'banana'],
array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges'];
var intersection = array1.filter(function(e) {
return array2.indexOf(e) > -1;
});
console.log(intersection);
You can also add this method on Array prototype and call it directly on array
Array.prototype.intersection = function(arr) {
return this.filter(function(e) {
return arr.indexOf(e) > -1;
});
};
var array1 = ['apples', 'grapes', 'oranges', 'banana'],
array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges'];
var intersection = array1.intersection(array2);
console.log(intersection);
You can use some, like this:
let newArray = array2.filter(
(array22) => !array1.some((array11) => array11.id === array22._id));
Hi this is a porting of the function array_intersect php. Should be good for you
http://phpjs.org/functions/array_intersect/
function array_intersect(arr1) {
// discuss at: http://phpjs.org/functions/array_intersect/
// original by: Brett Zamir (http://brett-zamir.me)
// note: These only output associative arrays (would need to be
// note: all numeric and counting from zero to be numeric)
// example 1: $array1 = {'a' : 'green', 0:'red', 1: 'blue'};
// example 1: $array2 = {'b' : 'green', 0:'yellow', 1:'red'};
// example 1: $array3 = ['green', 'red'];
// example 1: $result = array_intersect($array1, $array2, $array3);
// returns 1: {0: 'red', a: 'green'}
var retArr = {},
argl = arguments.length,
arglm1 = argl - 1,
k1 = '',
arr = {},
i = 0,
k = '';
arr1keys: for (k1 in arr1) {
arrs: for (i = 1; i < argl; i++) {
arr = arguments[i];
for (k in arr) {
if (arr[k] === arr1[k1]) {
if (i === arglm1) {
retArr[k1] = arr1[k1];
}
// If the innermost loop always leads at least once to an equal value, continue the loop until done
continue arrs;
}
}
// If it reaches here, it wasn't found in at least one array, so try next value
continue arr1keys;
}
}
return retArr;
}
You can use
const arr1 = [1, 2, 3];
const arr2 = [2, 3];
arr1.filter(e => arr2.indexOf(e) > -1 ? false : true); // [1]
Came here some week back to find a solution to a problem like this but its a pity I couldn't get what I wanted, but now I figured it out in a more simple way. using the arrow function, .filter() method and .includes() method.
Declare an arrow function that takes in two arguments:
const filterTwoArrays = (string1, string2) => string1.filter(item => string2.includes(item));
console.log(filterTwoArrays(array1, array2)).
Here is one simple way based on your code
function array_filter(filter, result) {
var filterLen = filter.length;
var resultLen = result.length;
for (i = 0; i < resultLen; i++) {
for (j = 0; j < filterLen; j++) {
if (!contains(filter, result[i]))
result.splice(i, 1);
}
}
}
//Return boolean depending if array 'a' contains item 'obj'
function contains(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
Since you have tagged javascript here is the solution.
function f1(x, y) {
var t = y.slice(0);
var r = [];
for (var i = 0; i < x.length; i++) {
for (var j = 0; j < y.length; j++) {
if (x[i] === y[j]) {
[].push.apply(r, t.splice(j, 1));
}
}
}
console.log(r)
y.length = 0;
[].push.apply(y, r);
}
Mark the items which are to be filtered out via delete result[index] manipulate them as needed.
JavaScript
window.onload = runs;
function runs() {
var array1 = ["apples", "grapes", "oranges"];
var array2 = ["potato", "pears", "grapes", "berries", "apples", "oranges"];
var result = filter_twoArrays(array1, array2);
function filter_twoArrays(filter, result) {
var i = 0,
j = 0;
for (i = 0; i < result.length; i++) {
var FLAG = 0;
for (j = 0; j < filter.length; j++) {
if (filter[j] == result[i]) {
FLAG = 1;
}
}
if (FLAG == 0) delete result[i];
}
return result;
}
var body = document.getElementsByTagName("body")[0];
var i = 0;
for (i = 0; i < result.length; i++) {
if (result[i] !== undefined)
body.innerHTML = body.innerHTML + result[i] + " ";
}
}
const func = array1.filter(item => array2.includes(item));
All I need to do is compare two arrays of objects and remove items in the second one that have the same property value. For example:
var a = [{'name':'bob', 'age':22}, {'name':'alice', 'age':12}, {'name':'mike', 'age':13}];
var b = [{'name':'bob', 'age':62}, {'name':'kevin', 'age':32}, {'name':'alice', 'age':32}];
function remove_duplicates(a, b) {
for (var i = 0, len = a.length; i < len; i++) {
for (var j = 0, len = b.length; j < len; j++) {
if (a[i].name == b[j].name) {
b.splice(j, 1);
}
}
}
console.log(a);
console.log(b);
}
console.log(a);
console.log(b);
remove_duplicates(a,b);
I cannot understand why this does not work and instead gives:
Uncaught TypeError: Cannot read property 'name' of undefined
What I expected was the following content in b:
[{'name':'kevin', 'age':32}];
FIDDLE
for (var i = 0, len = a.length; i < len; i++) {
for (var j = 0, len2 = b.length; j < len2; j++) {
if (a[i].name === b[j].name) {
b.splice(j, 1);
len2=b.length;
}
}
}
Instead of using two loops you might also use the findIndex function:
for (var i = 0, len = a.length; i < len; i++) {
var ItemIndex = b.findIndex(b => b.name === a[i].name);
a.splice(ItemIndex, 1)
}
Or if you want to go completely without using a loop you might use the forEach function
a.forEach(function(item, index, array) {
var ItemIndex = b.findIndex(b => b.name === item.name);
a.splice(ItemIndex, 1)
}
Your problem is, that splice() will change the length of the array, so that your precalculated len value will be too large and the inside the loop you try to access undefined elements.
A possible solution would be to use the filter() method:
function remove_duplicates(a, b) {
b = b.filter( function( item ) {
for( var i=0, len=a.length; i<len; i++ ){
if( a[i].name == item.name ) {
return false;
}
}
return true;
});
console.log(a);
console.log(b);
}
Example Fiddle
You just need to break the inner loop when a match is found:
if (a[i].name == b[j].name) {
b.splice(j, 1);
break;
}
Try this:
You are starting loop from the 0.
for (var i = 0, len = a.length; i < len; i++) {
for (var j = 0, len = b.length; j < len-1; j++) {
if (a[i].name == b[j].name) {
b.splice(j, 1);
}
}
}
Fiddle Demo
compare and remove in array of object.Typically array of object data type may be typeOf is object.So that we need to convert into JSON stringify and then check condition..
for(var i=0; i < a.length; i++) {
for(var j=0; j < b.length; j++) {
if(JSON.stringify(a[i]) == JSON.stringify(b[j])) {
a.splice(i, 1);
}
}
}
let A = [
{name: 'a', age: 20},
{name: 'b', age: 30},
{name: 'c', age: 10},
]
let B = [
{name: 'a', age: 20},
{name: 'b', age: 40},
{name: 'd', age: 10},
{name: 'e', age: 20},
{name: 'f', age: 10},
]
const compareName = (obj1, obj2)=>{
return (obj1.name === obj2.name);
}
const compareAll = (obj1, obj2)=>{
return (obj1.name === obj2.name && obj1.age=== obj2.age);
}
let output = B.filter(b=>{
let indexFound = A.findIndex(a => compareName(a, b));
return indexFound == -1;
})
Depending on which Objects you want to remove use:
compareName : Remove objects which have common name
compareAll : Remove objects which have both name & age common
Also to find common Objects list just add use return index != -1
PS: Refer my Github for Array Data Manipulation examples in Javascript
var a = [{ 'name': 'bob', 'age': 22 }, { 'name': 'alice', 'age': 12 }, { 'name': 'mike', 'age': 13 }, { 'name': 'keerthi', 'age': 62 }];
var b = [{ 'name': 'bob', 'age': 62 }, { 'name': 'kevin', 'age': 32 }, { 'name': 'alice', 'age': 32 }, { 'name': 'keerthi', 'age': 62 }];
a.map((firstObj) => {
b.map((compareObj, i) => {
if (firstObj.name === compareObj.name) {
b.splice(i, 1);
}
})
})
console.log(b)
The root cause is that you directly splice items from array b while you are in the for loop and pre condition is a and b have same number of items.