im trying to remove adjacent duplicates but instead of desired result (3 results) i'm getting only 2 results
my Expected Output:
[{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}}]
here is what i have tried:
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
var nArr = [];
for(var i = 0; i < arr.length;++i){
var key1 = Object.keys(arr[i]).join('');
var nLength = ((i + 1) > arr.length - 1 ) ? 0 : i + 1;
var key2 = Object.keys(arr[nLength]).join('');
if(key1 == key2) continue;
nArr.push(arr[i]);
}
console.log(nArr);
from the above result you can see one more element is missing
Easier to use filter:
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
let lastKey;
const filtered = arr.filter((item) => {
const key = Object.keys(item)[0];
if (key === lastKey) return false;
lastKey = key;
return true;
});
console.log(filtered);
If you're looking for adjacent keys, you should just track the latest key, and not compare all of them.
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
let result = [], prev_key = '', key;
for(let item of arr) {
key = Object.keys(item).sort().join();
if(key == prev_key) continue;
prev_key = key;
result.push(item);
}
console.log(result);
var arr =
[
{"mw://HOME_BIN":{"position":0}},
{"mw://diagnosis_HOME":{"position":3}},
{"mw://HOME_BIN":{"position":3}},
{"mw://HOME_BIN":{"position":3}}
];
var nArr = [];
arr.forEach((ar,index) => {
if(index === arr.length - 1) {
nArr.push(ar);
return;
}
if(JSON.stringify(ar) !== JSON.stringify(arr[index+1])){
nArr.push(ar);
}
})
console.log(nArr);
You can use JSON.stringify to compare whole objects instead of using single key, for your scalability
Related
I would like to transform an array into another separing its items depending on a string data, and, when there are two or more items together and none of them is is the limit string data i would like to join then by "/". Something like this:
const stringLimit = "aa";
let arrayData =["b","c","aa","aa","d","c","aa","f"];
result:
arrayResult=["b/c","d/c","f];
I have try this, however, I think that there should be a better way
let stringItem;
let totalRouteDevice = new Array();
for (let index = 0; index < arrayData.length; index++) {
const item = arrayData [index];
if(item!=='aa' && item !== 'bb') {
stringItem = stringItem!=""?`${stringItem}/${item}`:stringItem
} else if(stringRouteItem!=="") {
totalRoute.push(stringItem);
stringItem ="";
}
}
I have try this, however, I think that there should be a better way
let stringItem;
let totalRouteDevice = new Array();
for (let index = 0; index < arrayData.length; index++) {
const item = arrayData [index];
if(item!=='aa' && item !== 'bb') {
stringItem = stringItem!=""?`${stringItem}/${item}`:stringItem
} else if(stringRouteItem!=="") {
totalRoute.push(stringItem);
stringItem ="";
}
}
Not saying this is better but you could group your data using reduce, splitting it by stringLimit, and then joining the groups by / as follows:
const stringLimit = 'aa'
const arrayData = ["b","c","aa","aa","d","c","aa","f"]
let arr = []
arrayData.reduce((acc, item, i) => {
if (item !== stringLimit) {
acc.push(item)
} else {
if (acc.length) {
arr.push(acc)
}
acc = []
}
if (item !== stringLimit && i === arrayData.length - 1) {
arr.push(acc)
}
return acc
}, [])
let result = arr.map((i) => i.join('/'))
console.log(result)
I am trying to remove duplicate JSON Objects from the array in ServiceNow.
Tried below code but it does not remove the duplicate. I want to compare both name & city.
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
alert(splitlen.length);
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(uniqueArray.indexOf(splitlen[i].name)==-1)
{
uniqueArray.push(splitlen[i]);
}
}
alert(JSON.stringify(uniqueArray));
Expected output :
[{"name":"Pune","city":"India"}]
uniqueArray.indexOf doesn't work because you're comparing objects against strings (splitlen[i].name). Try to use .find() instead:
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(!uniqueArray.find(x => x.name === splitlen[i].name))
{
uniqueArray.push(splitlen[i]);
}
}
console.log(uniqueArray);
or
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
function compare(x){
return x.name === splitlen[i].name;
}
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(!uniqueArray.find(compare))
{
uniqueArray.push(splitlen[i]);
}
}
console.log(uniqueArray);
you can try this. Also one more thing your array declaration is not right, remove single quotes from array.
var arr1 = [{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}];
function getUniqueListByKey(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()]
}
var arr2 = getUniqueListByKey(arr1, "name")
console.log(arr2);
Please try the following example
const arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
const splitlen = JSON.parse(arr1);
const output = splitlen.reduce((previousValue, currentValue) => {
const { name, city } = currentValue;
const index = previousValue.findIndex(
(entry) => entry.name === name && entry.city === city
);
if (index === -1) {
return [...previousValue, currentValue];
}
return previousValue;
}, []);
console.log(output);
See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Put the records in a hashset. If there is collision in the hashset, there is duplicate. This approach is O(n) while comparing all pairs is $O(n^2)$.
I'm trying to get an answer, here's my idea:
Create a function to compare two objects then create a function to get the unique value
function isEquals(obj1, obj2) {
const aProps = Object.getOwnPropertyNames(obj1);
const bProps = Object.getOwnPropertyNames(obj2);
if (aProps.length !== bProps.length) {
return false;
}
for (let j = 0; j < aProps.length; j++) {
const propName = aProps[j];
if (JSON.stringify(obj1[propName]) !== JSON.stringify(obj2[propName])) {
return false;
}
} return true;
}
function getUnique(arr) {
var uniqueArray = [];
for (var item of arr) {
const uniqueItems = arr.filter(i => isEquals(item, i));
if (uniqueItems.length !== 0) {
uniqueArray.push(Object.assign({}, uniqueItems.shift()));
}
arr = arr.filter(i => !isEquals(item, i));
}
return uniqueArray;
}
Hope it helps!
I am trying to convert a string into a delimited object key but I need some assistance on how to iterate over the length of the array and join accordingly.
SET('my.delimited.string.of.unknown.length')
const SET = key => (state, val) => {
if(key.indexOf('.') !== -1) {
let array = key.split(".")
for (var i = 0; i < array.length; i++) {
// what should I do here?
}
// desired output based on array length
// state[ array[0] ][ array[1] ] = val
// state.my.delimited.string.of.unknown.length = val
}
}
One of those very rare usecases for reduce:
const keys = key.split(".");
const prop = keys.pop();
keys.reduce((acc, key) => acc[key], state)[prop] = val;
For sure that could also be done with a for loop:
let array = key.split("."), acc = state;
for (var i = 0; i < array.length - 1; i++) {
acc = acc[ array[i] ];
}
acc[ array.pop() ] = val;
For setting a value, you could split the path and reduce the path by walking the given object. If no object exist, create a new property with the name. Later assign the value.
function setValue(object, path, value) {
var keys = path.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}
var test = {};
setValue(test, "first.deep.property", 1);
setValue(test, "and.another.deep.property", 20);
console.log(test);
You could also do this with a single Array.reduce:
const makeObject = (arr, val, obj={}) => {
arr.split('.').reduce((r,c,i,a) => r[c] = i == a.length-1 ? val : {}, obj)
return obj
}
console.log(makeObject("first.deep.property", 1))
console.log(makeObject("and.another.deep.property", 20))
Here is my javascript array:
arr = ['blue-dots', 'blue', 'red-dots', 'orange-dots', 'blue-dots'];
With Javascript, how can I count the total number of all unique values in the array that contain the string “dots”. So, for the above array the answer would be 3 (blue-dots, orange-dots, and red-dots).
var count = 0,
arr1 = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i].indexOf('dots') !== -1) {
if (arr1.indexOf(arr[i]) === -1) {
count++;
arr1.push(arr[i]);
}
}
}
you check if a certain element contains 'dots', and if it does, you check if it is already in arr1, if not increment count and add element to arr1.
One way is to store element as key of an object, then get the count of the keys:
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
console.log(Object.keys(arr.reduce(function(o, x) {
if (x.indexOf('dots') != -1) {
o[x] = true;
}
return o
}, {})).length)
Try this something like this:
// Create a custom function
function countDots(array) {
var count = 0;
// Get and store each value, so they are not repeated if present.
var uniq_array = [];
array.forEach(function(value) {
if(uniq_array.indexOf(value) == -1) {
uniq_array.push(value);
// Add one to count if 'dots' word is present.
if(value.indexOf('dots') != -1) {
count += 1;
}
}
});
return count;
}
// This will print '3' on console
console.log( countDots(['blue-dots', 'blue', 'red-dots', 'orange-dots', 'blue-dots']) );
From this question, I got the getUnique function.
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
then you can add a function that counts ocurrences of a string inside an array of strings:
function getOcurrencesInStrings(targetString, arrayOfStrings){
var ocurrencesCount = 0;
for(var i = 0, arrayOfStrings.length; i++){
if(arrayOfStrings[i].indexOf(targetString) > -1){
ocurrencesCount++;
}
}
return ocurrencesCount;
}
then you just:
getOcurrencesInStrings('dots', initialArray.getUnique())
This will return the number you want.
It's not the smallest piece of code, but It's highly reusable.
var uniqueHolder = {};
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
arr.filter(function(item) {
return item.indexOf('dots') > -1;
})
.forEach(function(item) {
uniqueHolder[item] ? void(0) : uniqueHolder[item] = true;
});
console.log('Count: ' + Object.keys(uniqueHolder).length);
console.log('Values: ' + Object.keys(uniqueHolder));
Try this code,
arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
sample = [];
for (var i = 0; i < arr.length; i++) {
if ((arr[i].indexOf('dots') !== -1) && (sample.indexOf(arr[i]) === -1)){
sample.push(arr[i]);
}
}
alert(sample.length);
var arr = [ "blue-dots", "blue", "red-dots", "orange-dots", "blue-dots" ];
var fArr = []; // Empty array, which could replace arr after the filtering is done.
arr.forEach( function( v ) {
v.indexOf( "dots" ) > -1 && fArr.indexOf( v ) === -1 ? fArr.push( v ) : null;
// Filter if "dots" is in the string, and not already in the other array.
});
// Code for displaying result on page, not necessary to filter arr
document.querySelector( ".before" ).innerHTML = arr.join( ", " );
document.querySelector( ".after" ).innerHTML = fArr.join( ", " );
Before:
<pre class="before">
</pre>
After:
<pre class="after">
</pre>
To put this simply, it will loop through the array, and if dots is in the string, AND it doesn't already exist in fArr, it'll push it into fArr, otherwise it'll do nothing.
I'd separate the operations of string comparison and returning unique items, to make your code easier to test, read, and reuse.
var unique = function(a){
return a.length === 0 ? [] : [a[0]].concat(unique(a.filter(function(x){
return x !== a[0];
})));
};
var has = function(x){
return function(y){
return y.indexOf(x) !== -1;
};
};
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
var uniquedots = unique(arr.filter(has('dots')));
console.log(uniquedots);
console.log(uniquedots.length);
I have an array of arrays as follows:
[[3, 4], [1, 2], [3, 4]]
I wish to create a new array of arrays that has no duplicates, and has a count of the number of occurrences of each element in the first array:
[[3,4,2], [1,2,1]]
here is what I have so far:
var alreadyAdded = 0;
dataset.forEach(function(data) {
From = data[0];
To = data[1];
index = 0;
newDataSet.forEach(function(newdata) {
newFrom = newData[0];
newTo = newData[1];
// check if the point we are looking for is already added to the new array
if ((From == newFrom) && (To == newTo)) {
// if it is, increment the count for that pair
var count = newData[2];
var newCount = count + 1;
newDataSet[index] = [newFrom, newTo, newCount];
test = "reached here";
alreadyAdded = 1;
}
index++;
});
// the pair was not already added to the new dataset, add it
if (alreadyAdded == 0) {
newDataSet.push([From, To, 1]);
}
// reset alreadyAdded variable
alreadyAdded = 0;
});
I am very new to Javascript, can someone help explain to me what I'm doing wrong? I'm sure there is a more concise way of doing this, however I wasn't able to find an example in javascript that dealt with duplicate array of arrays.
Depending on how large the dataset is that you're iterating over I'd be cautious of looping over it so many times. You can avoid having to do that by creating an 'index' for each element in the original dataset and then using it to reference the elements in your grouping. This is the approach that I took when I solved the problem. You can see it here on jsfiddle. I used Array.prototype.reduce to create an object literal which contained the grouping of elements from the original dataset. Then I iterated over it's keys to create the final grouping.
var dataSet = [[3,4], [1,2], [3,4]],
grouping = [],
counts,
keys,
current;
counts = dataSet.reduce(function(acc, elem) {
var key = elem[0] + ':' + elem[1];
if (!acc.hasOwnProperty(key)) {
acc[key] = {elem: elem, count: 0}
}
acc[key].count += 1;
return acc;
}, {});
keys = Object.keys(counts);
for (var i = 0, l = keys.length; i < l; i++) {
current = counts[keys[i]];
current.elem.push(current.count);
grouping.push(current.elem);
}
console.log(grouping);
Assuming order of sub array items matters, assuming that your sub arrays could be of variable length and could contain items other than numbers, here is a fairly generic way to approach the problem. Requires ECMA5 compatibility as it stands, but would not be hard to make it work on ECMA3.
Javascript
// Create shortcuts for prototype methods
var toClass = Object.prototype.toString.call.bind(Object.prototype.toString),
aSlice = Array.prototype.slice.call.bind(Array.prototype.slice);
// A generic deepEqual defined by commonjs
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
function deepEqual(a, b) {
if (a === b) {
return true;
}
if (toClass(a) === '[object Date]' && toClass(b) === '[object Date]') {
return a.getTime() === b.getTime();
}
if (toClass(a) === '[object RegExp]' && toClass(b) === '[object RegExp]') {
return a.toString() === b.toString();
}
if (a && typeof a !== 'object' && b && typeof b !== 'object') {
return a == b;
}
if (a.prototype !== b.prototype) {
return false;
}
if (toClass(a) === '[object Arguments]') {
if (toClass(b) !== '[object Arguments]') {
return false;
}
return deepEqual(aSlice(a), aSlice(b));
}
var ka,
kb,
length,
index,
it;
try {
ka = Object.keys(a);
kb = Object.keys(b);
} catch (eDE) {
return false;
}
length = ka.length;
if (length !== kb.length) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
} else {
return false;
}
} else {
ka.sort();
kb.sort();
for (index = 0; index < length; index += 1) {
if (ka[index] !== kb[index]) {
return false;
}
}
}
for (index = 0; index < length; index += 1) {
it = ka[index];
if (!deepEqual(a[it], b[it])) {
return false;
}
}
return true;
};
// Recursive function for counting arrays as specified
// a must be an array of arrays
// dupsArray is used to keep count when recursing
function countDups(a, dupsArray) {
dupsArray = Array.isArray(dupsArray) ? dupsArray : [];
var copy,
current,
count;
if (a.length) {
copy = a.slice();
current = copy.pop();
count = 1;
copy = copy.filter(function (item) {
var isEqual = deepEqual(current, item);
if (isEqual) {
count += 1;
}
return !isEqual;
});
current.push(count);
dupsArray.push(current);
if (copy.length) {
countDups(copy, dupsArray);
}
}
return dupsArray;
}
var x = [
[3, 4],
[1, 2],
[3, 4]
];
console.log(JSON.stringify(countDups(x)));
Output
[[3,4,2],[1,2,1]]
on jsFiddle
After fixing a typo I tried your solution in the debugger; it works!
Fixed the inner forEach-loop variable name to match case. Also some var-keywords added.
var alreadyAdded = 0;
dataset.forEach(function (data) {
var From = data[0];
var To = data[1];
var index = 0;
newDataSet.forEach(function (newData) {
var newFrom = newData[0];
var newTo = newData[1];
// check if the point we are looking for is already added to the new array
if ((From == newFrom) && (To == newTo)) {
// if it is, increment the count for that pair
var count = newData[2];
var newCount = count + 1;
newDataSet[index] = [newFrom, newTo, newCount];
test = "reached here";
alreadyAdded = 1;
}
index++;
});
// the pair was not already added to the new dataset, add it
if (alreadyAdded == 0) {
newDataSet.push([From, To, 1]);
}
// reset alreadyAdded variable
alreadyAdded = 0;
});
const x = [[3, 4], [1, 2], [3, 4]];
const with_duplicate_count = [
...x
.map(JSON.stringify)
.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() )
.entries()
].map(([k, v]) => JSON.parse(k).concat(v));
console.log(with_duplicate_count);