JavaScript -- find matching object in array of objects - javascript

I am trying to search for an object in an array of objects.
Note, vals and recs objects will be DYNAMIC.
var vals = {ID: "4", LOC: "LA", SEQ: "1"};
var recs = [
{ID:"4", LOC:"LA", SEQ:"1"},
{ID:"4", LOC:"NY", SEQ:"1"},
{ID:"4", LOC:"CHI",SEQ:"1"}
];
Now I need to check if all key:value pairs in vals already exist in recs . In this case, recs[0] is an exact match of vals.
Heres my attempt:
var vals = {ID: "4", LOC: "LA", SEQ: "1"};
var recs = [
{ID:"4", LOC:"LA", SEQ:"1"},
{ID:"3", LOC:"NY", SEQ:"2"},
{ID:"2", LOC:"CHI",SEQ:"3"}
];
for(var i = 0; i<recs.length; i++){
if(recs[i]["ID"] == vals["ID"] && recs[i]["LOC"] == vals["LOC"] && recs[i]["SEQ"] == vals["SEQ"]){
console.log(true);
}
else{
console.log(false);
}
}
The above works only because I have hardcoded the keys from the vals object. In reality, the VALS object (and recs) will be DYNAMIC with X number of key:value pairs.
So how can I modify my for loop for a dynamic vals object?
thanks!

Try this:
for (var i = 0; i < recs.length; i++) {
var found = true;
for (var p in vals) {
if (vals.hasOwnProperty(p)) {
if (recs[i][p] !== vals[p]) {
found = false;
break;
}
}
}
console.log(found);
}

for(var i = 0; i<recs.length; i++) {
for (var prop in object) {
if (recs[i][prop] != vals[prop]) {
console.log(false);
return;
}
}
//check from both sides
for (var prop in vals) {
if (recs[i][prop] != vals[prop]) {
console.log(false);
return;
}
}
console.log(true);
}

You could iterate over the keys; something along the lines of:
var vals = { ID: "4", LOC: "LA", SEQ: "1", REGION: "USA" };
var recs = [{ ID: 4, LOC: "LA", SEQ: "1", REGION: "USA" },
{ ID: 3, LOC: "NY", SEQ: "2", REGION: "USA" },
{ ID: 2, LOC: "CHI", SEQ: "3", REGION: "USA" }
];
var isSame = true;
for (var i = 0; i < recs.length; i++) {
console.log( i + '----------------' );
var isSame = true;
// get the keys of the record
var keys = Object.keys(recs[i]);
for (var j = 0; j < keys.length; j++) {
var key = keys[j];
var record = recs[i]
console.log( key + ": " + record[key] + '=' + vals[key] );
if (record[key] != vals[key] ) {
isSame = false;// not equal
break;
}
}
console.log('isSame: ' + isSame );
console.log('------------------' );
}

You need to break it into two loops, one for each object of the array and one for each key of the object:
for(var i = 0; i<recs.length; i++){
var found = false
for(var key in recs[i]) {
if(recs[i].hasOwnProperty(key)){
if(recs[i][key] != vals[key]){
found = true
}
}
console.log(found)
}
the hasOwnProperty call will make sure it doesn't break if the object does not have that key.

You can try this:
function myFind(recs, vals) {
return recs.some(function(obj) {
for (var x in obj)
if (x in vals && obj[x] != vals[x])
return false;
return true;
});
}
var recs = [
{ID:4, LOC:"LA", SEQ:"1", USA:"USA"},
{ID:3, LOC:"NY", SEQ:"2", USA:"USA"},
{ID:2, LOC:"CHI",SEQ:"3", USA:"USA"}
];
var vals = {ID: "4", LOC: "LA", SEQ: "1"};
if (myFind(recs, vals)) {
alert('found');
} else {
alert('not found');
}
Hope it helps.

you can use underscorejs isEqual for this kind of problem

Related

Javascript: object array mapping and matching with IE11

I'm looking for a javascript implementation (for IE11) for this problem; my inputs are two arrays like these:
var array1 = [{id: 1, param:"bon jour"}, {id: 2, param:"Hi"}, {id: 3, param:"Hello"}];
var array2 = [{item: "Peter", values:"1,2", singlevalue:"2"},
{item: "Mark", values:"1,2,3", singlevalue:"3"},
{item: "Lou", values:"2", singlevalue:"2"}];
and I should create a new array (array3) with array2 data plus 2 new fields ("params" and "singleparam"), using matching between array1[i].id and array2[x].values to evaluate "params" and between array1[i].id and array2[x].singlevalue to evaluate "singleparam", with this kind of result:
array3 = [{item: "Peter", values:"1,2", singlevalue:"2", params:"bon jour,Hi", singleparam:"Hi"},
{item: "Mark", values:"1,2,3", singlevalue:"3", params:"bon jour,Hi,Hello", singleparam:"Hello"},
{item: "Lou", values:"2", singlevalue:"2", params:"Hi", singleparam:"Hi"}];
I'm a javascript newbie and I've tried this kind of solution:
var array3 = array2.map(function(x, array1)
{
const newOb = {};
newOb.item = x.item;
newOb.values = x.values;
newOb.singlevalue = x.singlevalue;
newOb.params = function(x.values, array1)
{
var str = "";
var idArray = x.values.split(",");
for(i = 0; i < idArray.lenght; i++)
{
for(j = 0; i < array1.lenght; j++)
{
if(idArray[i] == array1[j].id)
{
str += array1[j].param + ",";
break;
}
}
}
return str;
};
newOb.singleparam = function(x.singlevalue, array1)
{
var val;
for(j = 0; i < array1.lenght; j++)
{
if(array1[j].id == x.singlevalue)
val = array1[j].param;
}
return val;
}
return newOb;
});
console.log(array3);
with this error: Error: Unexpected token '.'
I'd like to find an efficient solution considering that array1 has less than 10 elements, but array2 could contains more than 1000 objects.
Thanks in advance for your support
I will skip the functions stop and singlevalues and there were also some syntax errors,
for example the correct one is length and not lenght
var array1 = [{id: 1, param:"bon jour"}, {id: 2, param:"Hi"}, {id: 3, param:"Hello"}];
var array2 = [{item: "Peter", values:"1,2", singlevalue:"2"},
{item: "Mark", values:"1,2,3", singlevalue:"3"},
{item: "Lou", values:"2", singlevalue:"2"}];
function newArray3() {
return array2.map(x => {
const newOb = {};
newOb.item = x.item;
newOb.values = x.values;
newOb.singlevalue = x.singlevalue;
newOb.params = paramsFunction(x.values, array1);
newOb.singleparam = singleParamFunction(x.singlevalue, array1);
return newOb;
})
}
function singleParamFunction(x, array1) {
var val;
for(i = 0; i < array1.length; i++) {
if(array1[i].id.toString() == x) {
val = array1[i].param;
}
}
return val;
}
function paramsFunction(x, array1) {
var str = "";
var idArray = x.split(",");
for(i = 0; i < idArray.length; i++)
{
for(j = 0; j < array1.length; j++)
{
if(idArray[i] == array1[j].id.toString())
{
str += array1[j].param + ",";
break;
}
}
}
return str;
}
array3 = newArray3();
console.log(array3)
The solution provided by the #Walteann Costa can show the desired results in other browsers but it will not work for the IE browser as his code sample uses the => Arrow functions that is not supported in the IE browser.
As your question asks the solution for the IE browser, I tried to modify the code sample provided by the #Walteann Costa. Below modified code can work with the IE 11 browser.
<!doctype html>
<html>
<head>
<script>
"use strict";
var array1 = [{
id: 1,
param: "bon jour"
}, {
id: 2,
param: "Hi"
}, {
id: 3,
param: "Hello"
}];
var array2 = [{
item: "Peter",
values: "1,2",
singlevalue: "2"
}, {
item: "Mark",
values: "1,2,3",
singlevalue: "3"
}, {
item: "Lou",
values: "2",
singlevalue: "2"
}];
function newArray3() {
return array2.map(function (x) {
var newOb = {};
newOb.item = x.item;
newOb.values = x.values;
newOb.singlevalue = x.singlevalue;
newOb.params = paramsFunction(x.values, array1);
newOb.singleparam = singleParamFunction(x.singlevalue, array1);
return newOb;
});
}
function singleParamFunction(x, array1) {
var val,i,j;
for (i = 0; i < array1.length; i++) {
if (array1[i].id.toString() == x) {
val = array1[i].param;
}
}
return val;
}
function paramsFunction(x, array1) {
var str = "";
var idArray = x.split(",");
var i,j;
for (i = 0; i < idArray.length; i++) {
for (j = 0; j < array1.length; j++) {
if (idArray[i] == array1[j].id.toString()) {
str += array1[j].param + ",";
break;
}
}
}
return str;
}
var array3 = newArray3();
console.log(array3[0]);
console.log(array3[1]);
console.log(array3[2]);
</script>
</head>
<body>
</body>
</html>
Output in the IE 11:

Remove duplicates from array of arrays by the first object

I have an array of arrays which looks like this:
arr = [
["Bob","USA","55"],
["Frank","Canada","20"],
["Bob","UK","35"],
["Bob","France","38"],
["Anna","Poland","22"]
]
I like to remove duplicate arrays which have the same value on the first position(the same name) - so I'd like to my output will look like that:
arr = [
["Bob","USA","55"],
["Frank","Canada","20"],
["Anna","Poland","22"]
]
I'm trying to do this in this way:
uniqueArr = []
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1)) {
uniqueArr.push(arr[i][0])
}
Everything works ok - my output looks like Bob, Frank, Anna
But the problem is when I'm trying to recive whole arrays with unique value name. When I'm doing:
uniqueArr = []
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1)) {
uniqueArr.push(arr[i])
}
My output looks exactly like the input array. Do you know where I'm doing wrong?
You could keep track of the key string in a separate array and track that instead, for example:
var uniqueArr = [],
keys = []; // Create an array for storing the key values
for (var i in arr) {
if (keys.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]); // Push the value onto the unique array
keys.push(arr[i][0]); // Push the key onto the 'key' array
}
}
console.log(uniqueArr);
jsFiddle example
try
arr = [
["Bob", "USA", "55"],
["Frank", "Canada", "20"],
["Bob", "UK", "35"],
["Bob", "France", "38"],
["Anna", "Poland", "22"]
]
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (isInArr(newArr, arr[i]) == -1) {
newArr.push(arr[i]);
}
}
function isInArr(checkArr, value) {
var index = -1;
for (var i = 0; i < checkArr.length; i++) {
if (checkArr[i][0] == value[0]) {
index = i;
break;
}
}
return index;
}
console.log(newArr)
DEMO
Take a look atthe function unique2. It works!
originalArr = [
["Bob", "USA", "55"],
["Frank", "Canada", "20"],
["Bob", "UK", "35"],
["Bob", "France", "38"],
["Anna", "Poland", "22"]
];
function unique(arr) {
uniqueArr = [];
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
}
function unique2(arr) {
uniqueArr = [];
keys = [];
for (var i in arr) {
if (keys.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]);
keys.push(arr[i][0]);
}
}
return uniqueArr;
}
var response = document.getElementById('response');
response.textContent = JSON.stringify(unique(originalArr));
var response2 = document.getElementById('response2');
response2.textContent = JSON.stringify(unique2(originalArr));
<h1>Your code</h1>
<div id="response"></div>
<h1>My code</h1>
<div id="response2"></div>

Getting index of array object element given multiple object keys

I know given a single key (for example, if I know the object.name = 'Sam') using:
var index = array.map(function(el) {return el.name}).indexOf('Sam');
I can get the index of the array element with object.name = 'Sam'
However say I have several elements with object.name ='Sam' in the array, but now I know know the object.name, object.age and object.size - is it possible to adapt the above code to get the index but also checking against object.age and object.size?
Assuming you have the values in variables such as name, age and size as you mentioned in comments, You can use a function like:
function findInArray(arr) {
for (var i = 0; i < arr.length; i++) {
var el = arr[i];
if (el.name == name && el.age == age && el.size == size)
return i;
}
return -1;
};
Which will return the index of object in array if match is found, and -1 otherwise...
var data = [{
name: "Sis",
age: "17",
size: "10"
}, {
name: "Sam",
age: "17",
size: "10"
}, {
name: "Som",
age: "17",
size: "10"
}],
name = "Sam",
age = "17",
size = "10";
function findInArray(arr) {
for (var i = 0; i < arr.length; i++) {
var el = arr[i];
if (el.name == name && el.age == age && el.size == size)
return i;
}
return -1;
};
console.log(findInArray(data));
If you're using the awesome underscore library there's a _.findWhere function.
var sam21 = _.findWhere(people, {
name: 'Sam',
age: 21
});
if you want something without a whole other library you can use .filter.
var sam21 = people.filter(function(person) {
return person.age === 21 && person.name === 'Sam';
});
I just noticed you're looking for the index. This answer can be useful: https://stackoverflow.com/a/12356923/191226
You could use a function like this one
indexOfObjectArray = function(array, keyvalues) {
for (var i = 0; i < array.length; i++) {
var trueCount = 0;
for (var j = 0; j < keyvalues.length; j++) {
if (array[i][keyvalues[j]['key']] == keyvalues[j]['value']) {
trueCount++;
}
}
if (trueCount === keyvalues.length) return i;
}
return -1; }
and use it like that for example:
var yourArray = [{id: 10, group: 20},...];
var keyvalues = [
{ 'key': 'id', 'value': 10 },
{ 'key': 'group', 'value': 20 }];
var index = indexOfObjectArray(yourArray, keyvalues );
This function will return the index of an object that has id = 10 and group = 20

Javascript: Parse array like search querystring

This is a string i have in my javascript
var searchString = City=20&Region=67&&Interests[8]=8&Interests[13]=13&Interests[4]=4&Duration[1]=Full+Day+Tour&Duration[3]=Evening+Tour&Duration[5]=2+Day+Short+Break&Departs[Fri]=Fri&Departs[Sat]=Sat&Departs[Sun]=Sun&TourLanguages=1&action_doSearch=Update
and i have a function
function loadDataFrom(request){
//if request if empty then return
if(request == "")
return;
var request = decodeURIComponent(request);
//if we get there then its likely we have a search query to process
var searchCriteria = request.split('&');
var hash = {};
for(var i = 0; i < searchCriteria.length; i++) {
var val = searchCriteria[i].split('=');
//we can safely ignore the "view" and 'action_doSearch' becuase they are not searched on
if(unescape(val[0]) === 'view' || unescape(val[0]) === 'action_doSearch')
continue;
//filter objects without any values
if(val[1] != '')
//add the names and values to our object hash
hash[unescape(val[0])] = unescape(val[1]);
}
//iterate over the hash objects and apply the current selection
$.each(hash, function(index, value) {
switch (index) {
case 'City':
case 'Region':
case 'TourLanguages':
//do stuff;
break;
case 'Duration[]':
case 'Departs[]':
//do something esle
default:
break;
}
});
};
that parses the URL parameters into an objecct hash with the following values.
City: "20"
Region: "67"
Departs[Fri]: "Fri"
Departs[Sat]: "Sat"
Departs[Sun]: "Sun"
Duration[1]: "Full+Day+Tour"
Duration[3]: "Evening+Tour"
Duration[5]: "2+Day+Short+Break"
Interests[4]: "4"
Interests[8]: "8"
Interests[13]: "13"
TourLanguages: "1"
but what i'd really like to do is to seperate the url into array like values like so
City: "20"
Region: "67"
Departs: ["Fri","Sat","Sun"]
Duration: ["Full+Day+Tour", "Evening+Tour", "2+Day+Short+Break"]
Interests: ["4", "8", "13"]
TourLanguages: "1"
Any help/pointers on this problem is greatly appreciated. Thanks in Advance
For something like this, to make it easier on myself I would write a RegExp to get the parts, then do some if logic to decide how to construct the Object.
var searchString = "City=20&Region=67&&Interests[8]=8&Interests[13]=13&Interests[4]=4&Duration[1]=Full+Day+Tour&Duration[3]=Evening+Tour&Duration[5]=2+Day+Short+Break&Departs[Fri]=Fri&Departs[Sat]=Sat&Departs[Sun]=Sun&TourLanguages=1&action_doSearch=Update",
o = {};
('&' + searchString)
.replace(
/&([^\[=&]+)(\[[^\]]*\])?(?:=([^&]*))?/g,
function (m, $1, $2, $3) {
if ($2) {
if (!o[$1]) o[$1] = [];
o[$1].push($3);
} else o[$1] = $3;
}
);
o; /*
{
"City": "20",
"Region": "67",
"Interests": ["8", "13", "4"],
"Duration": ["Full+Day+Tour", "Evening+Tour", "2+Day+Short+Break"],
"Departs": ["Fri", "Sat", "Sun"],
"TourLanguages": "1",
"action_doSearch": "Update"
} */
I would do it this way:
var str = 'City=20&Region=67&&Interests[8]=8&Interests[13]=13&Interests[4]=4&Duration[1]=Full+Day+Tour&Duration[3]=Evening+Tour&Duration[5]=2+Day+Short+Break&Departs[Fri]=Fri&Departs[Sat]=Sat&Departs[Sun]=Sun&TourLanguages=1&action_doSearch=Update',
strsplit = str.split(/&+/),
o = {};
for (var i = 0, l = strsplit.length; i < l; i++) {
var r = strsplit[i].match(/^([^=\[\]]+)(?:\[[^\]]+\])?=(.*)$/);
if (o[r[1]] === undefined) {
o[r[1]] = r[2];
} else if (o[r[1]].push) {
o[r[1]].push(r[2]);
} else {
o[r[1]] = [o[r[1]], r[2]];
}
}
This is a perfect scenario to use Map-Reduce and I recommend you to use underscore.js to implement something simple, elegant and more readable solution.
var m = _.map(searchString.split('&'), function (item) {
var parts = item.split('='), names = parts[0].split('[');
return [names[0], parts[1]];
});
var result = _.reduce(m, function(memo, item){
var key = item[0], value = item[1];
if(memo[key] === undefined) memo[key] = [value]
else memo[key].push(value)
return memo;
}, {});
console.log(result);

Need an algorithm to manipulate array structure in javascript

In javascript, here is my start array:
[{
name: 'aaa',
value: 1
},
{
name: 'bbb',
value: 0
},
{
name: 'bbb',
value: 1
}]
I want to transform it into this array as result:
[{
name: 'aaa',
value: 1
},
{
name: 'bbb',
value: [0, 1]
}]
I need a good and simple algorithm to do this
How about:
var array = [{
name: 'aaa',
value: 1
},
{
name: 'bbb',
value: 0
},
{
name: 'bbb',
value: 1
}];
var map = {};
for(var i = 0; i < array.length; i++) {
var name = array[i].name;
if (map[name] === undefined) {
map[name] = [];
}
map[name].push(array[i].value);
}
var result = [];
for(var key in map) {
var value = map[key];
result.push({
name: key,
value: value.length === 1 ? value[0] : value
});
}
Easiest way is to create a map to keep track of which names are used. Then convert this map back to an array of objects.
If you want to use Arrays for value then change it to:
result.push({
name: key,
value: value
});
here's pseudocode for simplest implementation
hash = {}
for(pair in array) {
hash[pair.name] ||= []
hash[pair.name] << pair.value
}
result = []
for(k, v in hash) {
result << {name: k, value: v}
}
This function does the trick
function consolidate(var arrayOfObjects)
{
// create a dictionary of values first
var dict = {};
for(var i = 0; i < arrayOfObjects.length; i++)
{
var n = arrayOfObjects[i].name;
if (!dict[n])
{
dict[n] = [];
}
dict[n].push(arrayOfObjects[i].value);
}
// convert dictionary to array again
var result = [];
for(var key in dict)
{
result.push({
name: key,
value: dict[key].length == 1 ? dict[key][0] : dict[key]
});
}
return result;
}
An alternative solution:
function convert(arr) {
var res = [];
var map = {};
for (var i=0;i<arr.length;i++) {
var arrObj = arr[i];
var oldObj = map[arrObj.name];
if (oldObj == undefined) {
oldObj = {name:arrObj.name, value:arrObj.value};
map[arrObj.name] = oldObj;
res.push(oldObj);
} else {
if( typeof oldObj.value === 'number' ) {
oldObj.value = [oldObj.value];
}
oldObj.value.push(arrObj.value);
}
}
return res;
}
In theory it should work a bit faster and use less memory. Basically it creates a result array and a map which is an index for the same array (no duplicate objects). So it fills the result in one iteration instead of two and does not need to convert map to array (which saves several CPU cycles :P ).
Added:
Here is a variation of that function in case value: [1] is acceptable:
function convert(arr) {
var res = [];
var map = {};
for (var i=0;i<arr.length;i++) {
var arrObj = arr[i];
var oldObj = map[arrObj.name];
if (oldObj == undefined) {
oldObj = {name:arrObj.name, value:[arrObj.value]};
map[arrObj.name] = oldObj;
res.push(oldObj);
} else {
oldObj.value.push(arrObj.value);
}
}
return res;
}

Categories

Resources