How can I count the duplicate property values of an object? - javascript

I have a list of emails in my object. Such as:
{
email1: yada#gmail.com,
email2: hada#gmail.com,
email3: hada#gmail.com
}
I want to find the duplicate emails, count the duplicates values for each and then within another object, show the number of duplicate emails found for each email.
How can I do this?

// Input
var input = {
email1: "yada#gmail.com",
email2: "hada#gmail.com",
email3: "hada#gmail.com"
}
var output = {};
for (var key in input) {
output[input[key]] = (output[input[key]] || 0) + 1;
}
for (var key in output) {
if (output[key] > 1) {
console.log(key, output[key]);
}
}
JSBIN

var input = {
email1: 'yada#gmail.com',
email2: 'hada#gmail.com',
email3: 'hada#gmail.com'
}
// first get a count of each:
var addressCount = Object.keys(input) // get the keys of the object
.map(function(k) { return input[k] }) // map to get an array of the addresses
.reduce(function(acc, email) { // reduce that array using an object
acc[email] = (acc[email] || 0) + 1 // to keep totals for each distinct email
return acc
}, {})
console.log(addressCount)
// then keep the ones with count > 1
var duplicates = Object.keys(addressCount)
.reduce(function(acc, email) {
if (addressCount[email] > 1)
acc[email] = addressCount[email]
return acc
}, {})
console.log(duplicates)

Hope this snippet will be useful
var obj = {
email1: 'yada #gmail.com',
email2: 'hada #gmail.com',
email3: 'hada #gmail.com'
}
var tempArray = []; // An array to track what is not duplicate
var newObj = {} // It is new object without duplicate
for (var keys in obj) {
// check in array if a key value is present
if (tempArray.indexOf(obj[keys]) === -1) {
// if not present add in the array, so next time it wont add again
tempArray.push(obj[keys]);
// in new object create a relevant key and add it's value
newObj[keys] = obj[keys]
}
}
console.log(newObj)
DEMO

You can try something like this:
Logic:
Create 2 objects,one for count and other for duplicates.
Loop over emails and set values in counts with necessary value.
If count is more than 1, set its value in dupes as well.
var input = {
email1: 'yada#gmail.com',
email2: 'hada#gmail.com',
email3: 'hada#gmail.com'
}
var counts = {};
var dupes = {};
for(var k in input){
var v = input[k];
var count = (counts[v] || 0) + 1;
counts[v] = count;
if(count > 1)
dupes[v] = count
}
console.log(counts, dupes)

Maybe something like this:
function countEmails(emails) {
return Object
.keys(emails)
.map(email => emails[email])
.reduce((counter, email) => {
return Object.assign({}, counter, {
[email]: counter[email] ? (counter[email] + 1) : 1,
});
}, {});
}
const emails = {
email1: 'asdf#asdf.asdf',
email2: 'asdf#asdf.asdf',
email3: 'qwer#qwer.qwer',
};
console.log(countEmails(emails)); // { 'asdf#asdf.asdf': 2, 'qwer#qwer.qwer': 1 }

Related

Check whether an Object contains a specific value in any of its array

How to find if an object has a value?
My Object looks like below: I have to loop through the object array and check if an array has "SPOUSE" in its value. if exist set a flag spouseExits = true and store the number (in this case (4 because [SPOUSE<NUMBER>] NUMBER is 4) in a variable 'spouseIndex'
This function needs to render in IE9 as well.
eligibilityMap = {
"CHIP": [
"CHILD5"
],
"APTC/CSR": [
"SELF1",
"CHILD2",
"CHILD3",
"SPOUSE4"
]
}
Code:
Object.keys(eligibilityMap).reduce(function (acc, key) {
const array1 = eligibilityMap[key];
//console.log('array1', array1);
array1.forEach(element => console.log(element.indexOf('SPOUSE')))
var spouseExist = array1.forEach(function (element) {
//console.log('ex', element.indexOf('SPOUSE') >= 0);
return element.indexOf('SPOUSE') >= 0;
});
//console.log('spouseExist', spouseExist);
return acc;
}, {});
SpouseIndex is undefined. What am I doing wrong?
Here's a simple approach, supports in all browsers including IE:
var spouseExists = false;
var spouseNumber;
for(var key in eligibilityMap)
{
for(var index in eligibilityMap[key])
{
if (eligibilityMap[key][index].indexOf("SPOUSE") > -1)
{
spouseExists = true;
spouseNumber = eligibilityMap[key][index].replace("SPOUSE", '');
break;
}
}
}
console.log(spouseExists, spouseNumber);
Solution 1: do 3 steps
You can use flatMap to get all sub-array into one.
use findIndex combined with startsWith to get exactly the index of SPOUSE
assign 2 variables based on the value of the found index.
const eligibilityMap = { "CHIP": [ "CHILD5" ], "APTC/CSR": ["SELF1","CHILD2","CHILD3","SPOUSE4"]};
let SpouseExits = false, SpouseIndex = 0;
const arrays = Object.values(eligibilityMap).flatMap(r => r);
const index = arrays.findIndex(str => str.startsWith("SPOUSE"));
if(index >= 0){
SpouseExits = true;
SpouseIndex = arrays[index].slice(-1);
}
console.log({SpouseExits, SpouseIndex});
Solution 2: This function renders in IE9 as well
const eligibilityMap = { "CHIP": [ "CHILD5" ], "APTC/CSR": ["SELF1","CHILD2","CHILD3","SPOUSE4"]};
let SpouseExits = false, SpouseIndex = 0;
for(const [key, value] of Object.entries(eligibilityMap))
{
const index = value.findIndex(function(str){ return str.startsWith("SPOUSE")});
if(index >= 0){
SpouseExits = true;
SpouseIndex = value[index].slice(-1);
}
}
console.log({SpouseExits, SpouseIndex});
Your condition element.indexOf('SPOUSE') >= 0 is not matching any value spouse on your array, because your array has no value named spouse SPOUSE it has SPOUSE4 though.
that's why it's returning undefined.
You may use regex instead of direct matching,
Object.keys(eligibilityMap).reduce(function (acc, key) {
const array1 = eligibilityMap[key];
//console.log('array1', array1);
// array1.forEach(element => console.log(element.indexOf('SPOUSE')))
// var spouseExist = -1;
var spouseExist = array1.filter(function (element,index) {
if(element.match(/SPOUSE/g)) return element; //fixes
});
//fixes
console.log('spouseExist',spouseExist.length>0)
if(spouseExist.length>0){
spouseExist.forEach(element => {
console.log('spouseIndex',element[element.length-1])
});
}
return acc;
}, {});
you can get the number from the spouse name directly, or you can access the index number of the matching spouse from inside the filter function using the value of index and do whatever you like.
Hope this matches your requirement.

typescript : logic to covert string array into custom object

Here is my requirement. I was able to achieve to some level in java but we need to move it to typescript (client side).
Note: The below input is for example purpose and may vary dynamically.
Input
var input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
We need to create an utility function that takes above input and returns output as below.
Output:
Should be string not an object or anything else.
"{ a { name, type }, b { city {name, zip } , desc }, c }"
any help is much appreciated.
I don't see that typescript plays any role in your question, but here's a solution for constructing the string you requested. I first turn the array into an object with those properties, then have a function which can turn an object into a string formatted like you have
const input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
const arrayToObject = (arr) => {
return arr.reduce((result, val) => {
const path = val.split('.');
let obj = result;
path.forEach(key => {
obj[key] = obj[key] || {};
obj = obj[key];
});
return result;
}, {});
}
const objectToString = (obj, name = '') => {
const keys = Object.keys(obj);
if (keys.length === 0) {
return name;
}
return `${name} { ${keys.map(k => objectToString(obj[k], k)).join(', ')} }`;
}
const arrayToString = arr => objectToString(arrayToObject(arr));
console.log(arrayToString(input));
Here's another variation. Trick is to parse the strings recursively and store the intermediate results in an Object.
function dotStringToObject(remainder, parent) {
if (remainder.indexOf('.') === -1) {
return parent[remainder] = true
} else {
var subs = remainder.split('.');
dotStringToObject(subs.slice(1).join('.'), (parent[subs[0]] || (parent[subs[0]] = {})))
}
}
var output = {};
["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"].forEach(function(entry) {
dotStringToObject(entry, output)
});
var res = JSON.stringify(output).replace(/\"/gi, ' ').replace(/\:|true/gi, '').replace(/\s,\s/gi, ', ');
console.log(res)
// Prints: { a { name, type }, b { city { name, zip }, desc }, c }
You could do something like this:
var input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
var output = {};
for(var i =0; i < input.length; i+=2){
output[String.fromCharCode(i+97)] = {};
output[String.fromCharCode(i+97)].name = input[i];
output[String.fromCharCode(i+97)].type = input[i+1];
}
console.log(JSON.stringify(output));

javascript loop on object with just one array

i've this structure of object which I need to loop on and find some value on the array ,e.g. find if user name is eq to user2 , I was able to do it with two object ( create another object and put there the array key like users, address etc ) but I want to know If I can do it with only on object,
This is sample of the object
var stuff = {
users :['user1','user2'],
address:['addr1', 'addr2'],
emails:['email1', 'email2'],
};
var stuff = {
users :['user1','user2'],
address:['addr1', 'addr2'],
emails:['email1', 'email2'],
}
console.log(Object.keys(stuff))
output will be
["users", "address", "emails"]
Iterate though content
assuming that you want find user2 in all keys of object.
keys = Object.keys(stuff)
for(let i in keys){
// do something
//console.log(stuff[keys[i]])
ind = stuff[keys[i]].indexOf('user2')
if(ind >=0){
console.log('user2 found in ', keys[i])
}
}
var stuff = {
users :['user1','user2'],
address:['addr1', 'addr2'],
emails:['email1', 'email2'],
};
function check(a) {
for(var key in stuff) {
var arr = stuff[key];
for(var i = 0; i < arr.length; i++) {
return arr[i] == a;
}
}
}
alert(check("user2"));
Check if the Array#indexOf of user2 in stuff.users is not -1:
var stuff = {
users: ['user1', 'user2'],
address: ['addr1', 'addr2'],
emails: ['email1', 'email2'],
};
var isUser2Included = stuff.users.indexOf('user2') !== -1;
console.log(isUser2Included);
Or so:
var stuff = {
users: ['user1', 'user2'],
address: ['addr1', 'addr2'],
emails: ['email1', 'email2'],
};
stuff.findIt = (key, val) => stuff[key].indexOf(val) != -1;
console.log(stuff.findIt('users', 'user1'));
console.log(stuff.findIt('users', 'user3'));
console.log(stuff.findIt('emails', 'email1'));

Cleaning the json object by removing duplicates and null and merging them into a single record

Cleaning the JSON object by removing duplicates and null and merging them into a single record
The json array looks like this:
var result =
[
{"id":"10035","occupation":null,"state":"FL"},
{"id":"10035","occupation":"doctor","state":null},
{"id":"10035","occupation":null,"state":null},
]
I want to merge records into one neglecting all the null fields and make it as a single record.Below is my expected output:
[
{"id":"10035","occupation":"doctor","state":"FL"}
]
You could do it with this ES6 script:
let data = [
{"id":"10035","occupation":null,"state":"FL"},
{"id":"10035","occupation":"doctor","state":null},
{"id":"10035","occupation":null,"state":null},
];
let result = Object.values(data.reduce ( (acc, {id, occupation, state}) => {
acc[id] = Object.assign({ id }, acc[id],
occupation && { occupation },
state && { state });
return acc;
}, {}));
console.log(result);
It will still produce multiple records if you have different id values in your input. When there are more than one non-null values for the other properties, but for the same id, then only the last one will survive.
When you're without support for Object.values
Use this definition of it:
Object.values = Object.values || (o => Object.keys(o).map(k => o[k]));
var final = {};
for (var i in result) {
for (var k in result[i]) {
if (result[i][k] && final[k] !== result[i][k]) {
final[k] = result[i][k];
}
}
}
console.log(final); // outputs: {id: "10035", state: "FL", occupation: "doctor"}
Here's a simple to understand example, which works for objects with any number of properties.
let data = [
{"id":"10035","occupation":null,"state":"FL"},
{"id":"10035","occupation":"doctor","state":null},
{"id":"10035","occupation":null,"state":null},
];
let result = data[0];
data.forEach(obj=> { // iterate through all objects in array
for(key in obj) // iterate through all properties of objects
if(obj[key]) result[key] = obj[key]; // if not null, assign to final result
});
console.log(result);
Here is a way to do it in O(n) time:
const mergeObjects = (data) => {
const dataWithoutDuplicates = {};
// first pass will get rid of dupes
let user;
for(let i = 0; i < data.length; data++) {
user = data[i];
if(!dataWithoutDuplicates[user.id]) {
dataWithoutDuplicates[user.id] = user
} else {
Object.keys(dataWithoutDuplicates[user.id]).forEach(key => {
if(dataWithoutDuplicates[user.id][key] === null && user[key]) {
dataWithoutDuplicates[user.id][key] = user[key]
}
})
}
return Object.values(dataWithoutDuplicates)
}

push only unique elements in an array

I have array object(x) that stores json (key,value) objects. I need to make sure that x only takes json object with unique key. Below, example 'id' is the key, so i don't want to store other json objects with 'item1' key.
x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = // could be "item1", "item2"....
var found = $.inArray(clickId, x); //
if(found >=0)
{
x.splice(found,1);
}
else{
x.push(new Item(clickId, obj)); //push json object
}
would this accomplish what you're looking for? https://jsfiddle.net/gukv9arj/3/
x = [
{"id":"item1","val":"Items"},
{"id":"item1","val":"Items"},
{"id":"item2","val":"Items"}
];
var clickId = [];
var list = JSON.parse(x);
$.each(list, function(index, value){
if(clickId.indexOf(value.id) === -1){
clickId.push(value.id);
}
});
You can't use inArray() because you are searching for an object.
I'd recommend rewriting a custom find using Array.some() as follows.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = "item1";
var found = x.some(function(value) {
return value.id === clickId;
});
alert(found);
Almost 6 years later i ended up in this question, but i needed to fill a bit more complex array, with objects. So i needed to add something like this.
var values = [
{value: "value1", selected: false},
{value: "value2", selected: false}
//there cannot be another object with value = "value1" within the collection.
]
So I was looking for the value data not to be repeated (in an object's array), rather than just the value in a string's array, as required in this question. This is not the first time i think in doing something like this in some JS code.
So i did the following:
let valueIndex = {};
let values = []
//I had the source data in some other and more complex array.
for (const index in assetsArray)
{
const element = assetsArray[index];
if (!valueIndex[element.value])
{
valueIndex[element.value] = true;
values.push({
value: element.value,
selected: false
});
}
}
I just use another object as an index, so the properties in an object will never be repated. This code is quite easy to read and surely is compatible with any browser. Maybe someone comes with something better. You are welcome to share!
Hopes this helps someone else.
JS objects are great tools to use for tracking unique items. If you start with an empty object, you can incrementally add keys/values. If the object already has a key for a given item, you can set it to some known value that is use used to indicate a non-unique item.
You could then loop over the object and push the unique items to an array.
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (itemsObj[item.id]) {
itemsObj[item.id] = "dupe";
}
else {
itemsObj[item.id] = item;
}
}
for (var myKey in itemsObj) {
if (itemsObj[myKey] !== "dupe") {
itemsList.push(itemsObj[myKey]);
}
}
console.log(itemsList);
See a working example here: https://jsbin.com/qucuso
If you want a list of items that contain only the first instance of an id, you can do this:
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (!itemsObj[item.id]) {
itemsObj[item.id] = item;
itemsList.push(item);
}
}
console.log(itemsList);
This is late but I did something like the following:
let MyArray = [];
MyArray._PushAndRejectDuplicate = function(el) {
if (this.indexOf(el) == -1) this.push(el)
else return;
}
MyArray._PushAndRejectDuplicate(1); // [1]
MyArray._PushAndRejectDuplicate(2); // [1,2]
MyArray._PushAndRejectDuplicate(1); // [1,2]
This is how I would do it in pure javascript.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}];
function unique(arr, comparator) {
var uniqueArr = [];
for (var i in arr) {
var found = false;
for (var j in uniqueArr) {
if (comparator instanceof Function) {
if (comparator.call(null, arr[i], uniqueArr[j])) {
found = true;
break;
}
} else {
if (arr[i] == uniqueArr[j]) {
found = true;
break;
}
}
}
if (!found) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
};
u = unique(x, function(a,b){ return a.id == b.id; });
console.log(u);
y = [ 1,1,2,3,4,5,5,6,1];
console.log(unique(y));
Create a very readable solution with lodash.
x = _.unionBy(x, [new Item(clickId, obj)], 'id');
let x = [{id:item1,data:value},{id:item2,data:value},{id:item3,data:value}]
let newEle = {id:newItem,data:value}
let prev = x.filter(ele=>{if(ele.id!=new.id)return ele);
newArr = [...prev,newEle]

Categories