lodash/underscore; compare two objects and remove duplicates - javascript

As you can see in the image below, I have some returned json data with three objects; each contains a clients id => data.
exact_match : {104}
match_4 : {104, 103}
match_2 : {104, 103, 68}
How can I "trim" or remove the duplicate objects based on previous ones? something like:
exact_match : {104}
match_4 : {103}
match_2 : {68}
I tried _.difference but did not work (Maybe because it is for arrays not objects?):
var exact_match = data.exact_match,
match_four_digits = _.difference(data.match_4, data.exact_match),
match_two_digits = _.difference(data.match_2, data.exact_match, data.match_4),
Any help would be appreciated :)
Update
I need that the returned value has the same object data instead of a new array :)

It looks like you want to diff keys (or rather, it'd be efficient to — _.keys)
_.difference(
_.keys({104: 1, 102: 3, 101: 0}), // ["104", "102", "101"]
_.keys({104: 1, 102: 3}) // ["104", "102"]
)
// [ "101" ]
Or, you could always convert your object to an array of pairs if you want to compare within the objects too (_.pairs):
_.difference(
_.pairs({104: 1, 102: 3, 101: 0}), // [["104",1], ["102",3], ["101",0]]
_.pairs({104: 1, 102: 2}) // [["104",1], ["102",2]]
)
// [["102", 3], ["101", 0]]

I would create a map called unique, e.g. var unique = {}; and then iterate over each key in your data and check if it's in unique. If it is in unique, delete the entry associated with that key, thus removing duplicates.
You could pull this check out as an alreadyFound method:
var alreadyFound = function (key) {
if (!(key in unique)) {
unique[key] = true;
return false;
}
return true;
};
Then iterate over your data and check alreadyFound(key) for key in your data, and delete the key if alreadyFound(key) returns true.
You could go messing with lodash/underscore methods but those might be inefficient depending on how you use them (and how they're implemented) and this should operate in linear time.
It looks like for your specific use case the full solution would be something like:
var unique = {};
// Assume I copy and pasted alreadyFound here
var alreadyFound = ...;
for (var object in data) {
// Iterate through ids in each object in data
for (var id in object) {
// Remove this entry if it's already found
if (alreadyFound(id)) {
delete object[id];
}
}
}

Thanks guys for the answers, I really appreciate your time.
I searched further and found this post by Lodash developer that helped me came up with this snippet;
var data = {
exact_match: {
104: {
supplier_id: 104
}
},
match_four_digits: {
104: {
supplier_id: 104
},
68: {
supplier_id: 68
}
},
match_two_digits: {
104: {
supplier_id: 104
},
68: {
supplier_id: 68
},
103: {
supplier_id: 103
},
999: {
supplier_id: 999
}
}
};
var arr_match_four_digits = _.difference(_.keys(data.match_four_digits), _.keys(data.exact_match));
var arr_match_two_digits = _.difference(_.keys(data.match_two_digits), _.keys(data.match_four_digits), _.keys(data.exact_match));
$('#output1').html(JSON.stringify(data));
$('#output2').html(JSON.stringify(_.pick(data.match_four_digits, arr_match_four_digits)));
$('#output3').html(JSON.stringify(_.pick(data.match_two_digits, arr_match_two_digits)));
<script src="https://cdn.rawgit.com/lodash/lodash/3.3.1/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
data
<pre><code><div id="output1"></div></code></pre>
arr_match_four_digits
<pre><code><div id="output2"></div></code></pre>
match_two_digits
<pre><code><div id="output3"></div></code></pre>

Related

How does one detect and access numbered property names like 'entry1', 'entry2'?

A data structure similar to the following provided ...
{
strIngredient1: 'Olive Oil',
strIngredient2: 'Onion',
strIngredient3: 'Chicken Breast',
strMeasure1: '',
strMeasure2: '',
keyWithNoIndexCount: '',
}
... needs to be processed.
How could one use a loop in order to generate the number count within keys like strIngredient1, strIngredient2, ... and so on?
I am having trouble working out which terms to search for. I want to use a for loop so each number after strIngredient would be i.
I want to grab each entry like that ... strIngredient + i ... and add them to an array but I do not know how to access them like this, if it is even possible or the best way. I do not know how to link the two parts of the following pseudo code ...
const ingredList = [];
for(i = 1; i < 20; i++) {
ingredList.push(response.meals[0].strMeasure ? );
ingredList.push(response.meals[0].strIngredient ? );
}
console.log(ingredList);
Edit 1
There are also additional but non related entries in the data-structure.
Edit 2
There are also additional keys like strMeasure1, strMeasure2, strMeasure3 etc. I want to access them too in addition to the already mentioned strIngredient based ones.
You can achieve that in two ways:
A: Grab values of all keys, regardless of key:
const jsonObj = {
"strIngredient1": "Olive Oil",
"strIngredient2": "Onion",
"strIngredient3": "Chicken Breast"
};
let ingredListA = Object.keys(jsonObj).map(key => jsonObj[key]);
console.log('ingredListA:', ingredListA);
C: Grab values of by named & numbered keys:
const jsonObj = {
"strIngredient1": "Olive Oil",
"strIngredient2": "Onion",
"strIngredient3": "Chicken Breast"
};
let ingredListB = [];
for(let i = 1; i <= 3; i++) {
let key = 'strIngredient' + i;
ingredListB.push(jsonObj[key]);
}
console.log('ingredListB:', ingredListB);
If needed you could add a 3rd solution that is a hybrid of A and B: Loop through all object keys, use value only of key matches desired pattern.
The OP needs a generic approach in order to parse from any given property-name the constant key part and the serial index. Like with a property name of 'strIngredient2' where the constant key is 'strIngredient' and the index is '2'.
One would achieve this via the usage of a regex like /(?<key>.*?\D)(?<index>\d*$)/ which features named capturing groups.
The regex-based parsing is part of a callback-function which does reduce the entries of the OP's provided object.
In order to stay even more generic by taking into account the renaming of some or all of the original object's property-names one would provide an object-based initial (reduce) value which features both,
a lookup for renaming some or all of the original property-names
and the result object which will feature any entry one would expect according to the OP's acceptance-criteria and the additional renaming.
function collectSerialEntry({ renaming, result }, [propName, value]) {
const regXSerialKey = /(?<key>.*?\D)(?<idx>\d*$)/;
let { key = null, idx = null } = regXSerialKey
.exec(propName)
?.groups ?? {};
if (key !== null) {
key = renaming[key] ?? key;
if (idx !== null) {
idx = parseInt(idx, 10);
idx = Number.isNaN(idx) && 1 || idx;
// - create and/or access the `key` related array
// and assign the value according to the
// retrieved index.
(result[key] ??= [])[idx - 1] = value;
} else {
// - assign the value according to its current key.^
result[key] = value;
}
}
return { renaming, result };
}
const sampleData = {
strIngredient1: 'Olive Oil',
strIngredient2: 'Onion',
strIngredient3: 'Chicken Breast',
strMeasure1: '100 ml',
strMeasure2: '2',
strMeasure3: '4',
strDescription: 'Start frying ... lorem ipsum dolor sit amet.',
};
const {
result: {
ingredientList,
measureList,
description,
},
} = Object
.entries(sampleData)
.reduce(collectSerialEntry, {
// - provide an initial value ...
renaming: {
strIngredient: 'ingredientList',
strMeasure: 'measureList',
strDescription: 'description',
},
// ... which features a lookup
// for renaming some or all of
// the original property-names ...
//
// ... and the `result` object
// which will feature any entry
// one would expect according to
// the OP's acceptance-criteria
// and the additional renaming.
result: {},
});
console.log(sampleData, ' => ', {
ingredientList,
measureList,
description,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }

Dynamically create array of objects, from array of objects, sorted by an object property

I'm trying to match and group objects, based on a property on each object, and put them in their own array that I can use to sort later for some selection criteria. The sort method isn't an option for me, because I need to sort for 4 different values of the property.
How can I dynamically create separate arrays for the objects who have a matching property?
For example, I can do this if I know that the form.RatingNumber will be 1, 2, 3, or 4:
var ratingNumOne = [],
ratingNumTwo,
ratingNumThree,
ratingNumFour;
forms.forEach(function(form) {
if (form.RatingNumber === 1){
ratingNumOne.push(form);
} else if (form.RatingNumber === 2){
ratingNumTwo.push(form)
} //and so on...
});
The problem is that the form.RatingNumber property could be any number, so hard-coding 1,2,3,4 will not work.
How can I group the forms dynamically, by each RatingNumber?
try to use reduce function, something like this:
forms.reduce((result, form) => {
result[form.RatingNumber] = result[form.RatingNumber] || []
result[form.RatingNumber].push(form)
}
,{})
the result would be object, with each of the keys is the rating number and the values is the forms with this rating number.
that would be dynamic for any count of rating number
You could use an object and take form.RatingNumber as key.
If you have zero based values without gaps, you could use an array instead of an object.
var ratingNumOne = [],
ratingNumTwo = [],
ratingNumThree = [],
ratingNumFour = [],
ratings = { 1: ratingNumOne, 2: ratingNumTwo, 3: ratingNumThree, 4: ratingNumFour };
// usage
ratings[form.RatingNumber].push(form);
try this its a work arround:
forms.forEach(form => {
if (!window['ratingNumber' + form.RatingNumber]) window['ratingNumber' + form.RatingNumber] = [];
window['ratingNumber' + form.RatingNumber].push(form);
});
this will create the variables automaticly. In the end it will look like this:
ratingNumber1 = [form, form, form];
ratingNumber2 = [form, form];
ratingNumber100 = [form];
but to notice ratingNumber3 (for example) could also be undefined.
Just to have it said, your solution makes no sense but this version works at least.
It does not matter what numbers you are getting with RatingNumber, just use it as index. The result will be an object with the RatingNumber as indexes and an array of object that have that RatingNumber as value.
//example input
var forms = [{RatingNumber:5 }, {RatingNumber:6}, {RatingNumber:78}, {RatingNumber:6}];
var results = {};
$.each(forms, function(i, form){
if(!results[form.RatingNumber])
results[form.RatingNumber]=[];
results[form.RatingNumber].push(form);
});
console.log(results);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HIH
// Example input data
let forms = [{RatingNumber: 1}, {RatingNumber: 4}, {RatingNumber: 2}, {RatingNumber: 1}],
result = [];
forms.forEach(form => {
result[form.RatingNumber]
? result[form.RatingNumber].push(form)
: result[form.RatingNumber] = [form];
});
// Now `result` have all information. Next can do something else..
let getResult = index => {
let res = result[index] || [];
// Write your code here. For example VVVVV
console.log(`Rating ${index}: ${res.length} count`)
console.log(res)
}
getResult(1)
getResult(2)
getResult(3)
getResult(4)
Try to create an object with the "RatingNumber" as property:
rating = {};
forms.forEach(function(form) {
if( !rating[form.RatingNumber] ){
rating[form.RatingNumber] = []
}
rating[form.RatingNumber].push( form )
})

How to declare a Hash/Dictionary of Array

I have a program that pushes values into one data structure like this:
if(symbolType == "C" || symbolType == "P") // The calls and puts
stocks.push({
symbol: symbol,
undsymbol: undSymbol,
open: 0,
type: symbolType,
expiry: expiry,
days: days,
strike: strike
});
}
else // The stock
{
stocks.push({
symbol: symbol,
open: 0,
type: symbolType
});
}
So this is the key: NOT A STRING!
{
symbol: symbol,
open: 0,
type: symbolType
}
And the values of which are many look like this:
{
symbol: symbol,
undsymbol: undSymbol,
open: 0,
type: symbolType,
expiry: expiry,
days: days,
strike: strike
}
The problem is that stocks and calls and puts are being put into one collection. Instead, I want to add the the stocks and their corresponding calls and puts into a dictionary/map, where the stocks are the keys, and the calls and puts get pushed into an array indexed by it's stock.
At the end, I want to be able to iterate and get the keys and values.
How do I declare this object
Index into it to see if the key[stock] already exists, if it doesn't add it with an empty array.
If I get a "C" or "P", I want to get the corresponding array that holds the Calls/Puts for this key [stock] and push the call/put into the array.
Initially I thought the declaration was something like this:
var stockCallsPutDict = {[]}
stockCallsPutDict[stock] = [];
stockCallsPut[stock].push(call);
// Pretty print the dict of keys and its options =
stockCallsPutDict.forEach(function kvp) {
...
}
If ES6 is an option, you can either build an object yourself or use a Map.
Here's some quick code I came up with:
const stocks = {};
const addCallAndPut = callAndPut => {
const symbol = callAndPut.symbol;
if (!stocks[symbol]) {
stocks[symbol] = [];
}
stocks[symbol].push(callAndPut);
}
const showStuff = () => {
for (const symbol in stocks) {
// output stuff using stocks[symbol]
}
}
OR WITH A MAP
const stocks = new Map();
// basic implementation
const addCallAndPut = callAndPut => {
const stockCallsAndPuts = stocks.get(callAndPut.symbol) || [];
stockCallsAndPuts.push(callAndPut);
stock.set(callAndPut.symbol, stockCallsAndPuts);
}
There are a few ways to go about this, and the best depends on how the data needs to be processed later, but from your description I'd go with something along the lines of
var stocks = {};
var stockCallsPut = {};
// loop over stocks and actions
if (!(symbol in stocks)) {
stocks[symbol] = [];
}
if (!(symbol in stockCallsPut)) {
stockCallsPut[symbol] = {};
}
if (!(symbolType in stockCallsPut[symbol])) {
stockCallsPut[symbol][symbolType] = [];
}
// accumulated stock json items here
stocks[symbol].push(new_stock_item);
// accumulated push/call json items of stock here
stockCallsPut[symbol][symbolType].push(new_action);
I'm still not sure I actually understood what your data looks like, but sounds kind of like this to me:
// Not sure if data is an object or array
var data = {
'one': {
'name': 'one-somename',
'number': 'one-somenumber',
'symbol': 'C'
},
'two': {
'name': 'two-somename',
'number': 'two-somenumber',
'symbol': 'P'
},
'three': {
'name': 'three-somename',
'number': 'three-somenumber',
'symbol': 'C'
}
};
var stocks = {};
for (var name in data) {
// It sounded like you wanted a call/put array for each object but I'm not sure if that's true since it wouldn't be possible... if so can just divide this part up into it's appropriate place in the if statement below
// Checking that the property is set on the object, if it is, it uses itself, otherwise it adds it with the call/put arrays created
stocks[name] = stocks[name] ? stocks[name] : {'calls': [], 'puts': []};
var type;
if (data[name]['symbol'] === 'C') {
type = 'calls';
} else if (data[name]['symbol'] === 'P') {
type = 'puts';
}
stocks[name][type].push(data[name]);
}

jQuery Convert Object Array to Array with keys

I have an object array which looks like:
Object {0: "Ma. Jessa Martinez", 1: "Edwin Cuevas", 2: "Gerum Generol", 3: "Roy delos Reyes", 4: "Hannah Montecillo", 5: "Ralph Turla", 6: "Edralyn Danabar", 7: "Angelo Sto Domingo", 8: "Rhina Dela Cruz", 9: "Ricardo Camara", 10: "Joene Floresca"}
And I want to convert in array like:
[[0,"Ma. Jessa Martinez"],[1,"Edwin Cuevas"],[2,"Gerum Generol"], and so on]
I tried using
var myobj_array= $.map(ticks, function(value, index) {
return [value];
});
But it only return the values with no keys:
["Ma. Jessa Martinez", "Edwin Cuevas", "Gerum Generol", "Roy delos Reyes", "Hannah Montecillo", "Ralph Turla", "Edralyn Danabar", "Angelo Sto Domingo", "Rhina Dela Cruz", "Ricardo Camara", "Joene Floresca"]
Is there other way? I've search already in google I can't find a similar thing.
EDIT To be clear where my object array came from, I added this for reference. It came from an ajax request and already sorted:
var ticks = {};
$.each(result, function(key,value) {
ticks[key] = value.name;
});
Use instead :
var myobj_array= $.map(ticks, function(value, index) {
return [[index,value]];
});
console.log(myobj_array);
#PinkTurtle point is important, because we may pay attention to the performance or use vanillajs instead jQuery.
However if the object structure use instead :
{80: "Ma. Jessa Martinez", 12: "Edwin Cuevas"}
and we process with only the index (and we retrieve it like arr[80] would be undefined, only if we use arr[0] would work, but the index of the user is not 0 , is 80).
Or just use normal js:
var arr = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
arr.push([i, obj[i]]);
}
}
You may create a new Javascript object and return as follow:
var myobj_array= $.map(ticks, function(value, index) {
Var obj=[[index,value]];
return obj;
});

Assign conditions/categories to elements in array

I have an array of words - my stimuli - and they are presented on the screen. Yet, each word has another "condition", that is they are either, say categoryA, categoryB, or categoryC. This is probably simple, but I couldn't find an answer and am stuck with it.
My final aim is to assign the categories randomly to the stimuli each time the script is run.
var stim = [ "AEROPLANE", "TRAIN", "CAR", "BIKE", "WALKING"];
Here I'd like AEROPLANE to have categA, TRAIN categB, and the rest categC.
I thought about something like this (or with integers instead of Letters):
var stim = [ ["AEROPLANE", A], ["TRAIN", B], ["CAR", C], ["BIKE", C], ["WALKING",C] ];
But this doesn't work. If I have categories, how would I access them to code responses?
This is the script that presents the stimuli (on each keypress a new one):
$(function(){
$(document).keypress(function(e){
if ($(e.target).is('input, textarea')) {
return;
};
if (e.which === 97 || e.which === 108) {
new_word = w_stim[Math.floor(Math.random() * stim.length)];;
$("#abc").text(new_word);
};
});
});
Make an array of objects:
var stim = [
{name:"AEROPLANE", category:"A"},
{name:"TRAIN", category:"B"},
{name:"CAR", category:"C"},
{name:"BIKE", category:"C"},
{name:"WALKING",category:"C"}
];
Then access the objects like:
stim[i].name
stim[i].category
JS Fiddle: http://jsfiddle.net/pJ6X2/
Another option would be
var stim = {
'A': ['AEROPLANE'],
'B': ['TRAIN'],
'C': ['CAR', 'BIKE', 'WALKING']
}
var items = stim[categoryChar];
if (undefined === items)
console.log('no such category');
else
console.log(items[Math.floor(Math.random() * items.length)]);

Categories