Array selector function by property value - javascript

I have:
var array = [ { key: '1' }, { key: '2' }, { key: '3' } ]
I want:
var obj = getFirstItem(array, 'key', '2');
And as a result:
obj = { key: '2' }
Is there such function in JavsScript or jQuery?

I don't know of a built in function. However, it would be trivial to implement it yourself:
var data = [ { key: '1' }, { key: '2' }, { key: '3' } ];
function getFirstItem(input, key, value) {
for(var i = 0; i < input.length; i++) {
if(input[i][key] === value)
return input[i];
}
}
console.log(getFirstItem(data, "key", 2));

I don't think jQuery is really necessary here. The function is as simple as:
function getFirstItem(arr, k, v){
for(var i=0;i<arr.length;i++){
var obj = arr[i];
if(obj[k] == v)
return obj;
}
return null;
}
Live example: http://jsfiddle.net/QARAd/

Like others have said it's quite simple to just loop over the array yourself.
However there is a filter method in JS 1.5 (Apparently not supported in IE8 and lower, although the link has a compatibility work around)
var myarray = [ { key: '1' }, { key: '2' }, { key: '3' } ]
function getFirstItem(myarray, key) {
var result = myarray.filter(function(element, index, array) {
return element.key == key;
});
if (result.length)
return result[0];
return null;
}
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
JSFiddle Example

Related

how to use .include() method to check the value which is in a json inside array

I want to compare the value of a particular key in my JSON array with new value to check whether the value exists or not.
For example, I have an array:
[
{ name: abc, num: 121212 },
{ name: bcd, num: 21212 },
{ name: def, num: 111222 }
]
Now a new value comes which I want to check. Does that name already exist? If it does, then I only want to update the number and if not then I want to push the object in the array.
Here is my code:
if ((Dnum.num).includes(number)) {
console.log("inside if");
console.log(Dnum.indexOf(number));
} else {
Dnum.push({num:number,
lat:lat,
lng:lng,
name:name
});
}
Well, your problem (if I understand correctly) is that you want to use includes() but what you actually want to accomplish doesn't correspond to what the method does. You want to find if there's an object with a certain name in your array already, not if it contains a known element. Something like this:
var data = [{name: 'abc', num: 121212}, {name: 'bcd', num: 21212}, {name: 'def', num: 111222}];
function addOrUpdate(newElement, data) {
var i;
for (i = 0; i < data.length; i++) {
if (data[i].name == newElement.name) {
data[i] = newElement;
return;
}
}
data.push(newElement);
}
addOrUpdate({name: 'bcd', num: 131313}, data);
console.log(data);
addOrUpdate({name: 'new', num: 131313}, data);
console.log(data);
Problem:
Actually .includes() and .indexOf() methods won't work with objects, they should be used with an array of strings or Numbers as they use strict equality to compare the elements and objects can't be compared this way, so you need to implement this logic by yourself.
Solution:
You need to check if an object matching the searched name already exists in the array, update the num value of this object, otherwise if no object matches the searched name, push the new object to the array:
if (arr.some(function(obj) {
return obj.name === searchedVal.name;
})) {
arr.forEach(function(el, index) {
if (el.name === searchedVal.name) {
el.num += searchedVal.num;
found = true;
}
});
} else {
arr.push(searchedVal);
}
Demo:
var arr = [{
name: "abc",
num: 121212
}, {
name: "bcd",
num: 21212
}, {
name: "def",
num: 111222
}];
var searchedVal = {
name: "abc",
num: 5
};
if (arr.some(function(obj) {
return obj.name === searchedVal.name;
})) {
arr.forEach(function(el, index) {
if (el.name === searchedVal.name) {
el.num += searchedVal.num;
found = true;
}
});
} else {
arr.push(searchedVal);
}
console.log(arr);
If you don't want to use .some() method, you can do it this way:
var searchedVal = {
name: "abc",
num: 5
};
var found = false;
arr.forEach(function(el, index) {
if (el.name === searchedVal.name) {
el.num+= searchedVal.num;
found = true;
}
});
if (!found) {
arr.push(searchedVal);
}
Use Array.prototype.find():
var res = Dnum.find(function (item) {
return item.num === number;
});
if (res) {
console.log("inside if");
console.log(res);
res.num = number;
} else {
Dnum.push({
num:number,
lat:lat,
lng:lng,
name:name
});
}

How to get the value from an array which has key/value pair objects?

In the below array, I have objects with key/value pairs
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
},
{
key: "second",
value: "Second Option"
}];
how to get the value based on key from options array?
For example, if the key is "select" it should return null,
if the key is "one" it should return "First Option".
ES6 has the find-function for arrays:
var val = options.find(function(o){ return o.key==="select" }).value;
And maybe wrap it in a function of your own to make it a bit more reusable:
function findValue(arr, key){
return arr.find(function(o){ return o.key===key }).value;
}
var val = findValue(options,"select");
I would argue this is the most semantically correct answer without modifying the original array, but you must have realized by now that there are many ways to skin this cat. (I like Zodiac Zubeda's answer because it's a simple for-loop so fast and backwards compatible and has the break that skips unnecessary iterations.)
You can search for the object you want from the array, then get the value of that object:
var value;
// Loop through the options array
for (var i = 0; i < options.length; i++) {
// If the key for this iteration's element is desired
if (options[i].key == "select") {
// Set the value to appropriately and exit the loop
value = options[i].value;
break;
}
}
This code makes "value" equal to the value you want, based on your key. If you want to determine the value multiple times, you can wrap the code in a function and return value. You'd probably also want to add a parameter for the desired key, and replace options[i].key == "select" with "options[i].key == <parameter name>".
Alternatively, you can structure your objects like so:
var options = {
"select": null,
"one": "First Option",
"second": "Second Option"
};
With this, you can access the value of a desired key like so:
options[<desired key>]
So, options["select"] would return null.
Using Array.prototype.filter (modern browsers and IE9+):
options.filter(function(opt) {
return opt.key === 'one';
})[0].value;
Or a one-liner using ES6 arrow notation:
options.filter(opt => opt.key === 'one')[0].value;
Reusable function, returning null if a match is not found:
function findValueByKey(opts, key) {
var match = opts.filter(function(opt) {
return opt.key === key;
});
return match[0] ? match[0].value : null;
}
JSFiddle: https://jsfiddle.net/02oawajt/3/
You have to brute force it...
function findValueForOption(key) {
for (i = 0; i < options.length; i++) {
if (options[i].key === key) {
return options[i].value;
}
}
return null; // Or do whatever you feel is appropriate when an unspecified key is requested...
}
Arraymap use to find key and value
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
},
{
key: "second",
value: "Second Option"
}];
var run = options.map(function (item,index) {
var fullname = 'the key='+item.key+',and value='+item.value;
return fullname;
})
console.log(run);
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
}, {
key: "second",
value: "Second Option"
}];
// output values of whatever you like
checkValue("select");
console.log("------------------------------");
checkValue("one");
console.log("------------------------------");
checkValue("second");
console.log("------------------------------");
function checkValue(val) {
for (var i = 0; i < options.length; i++) {
if(options[i].key == val){
console.log("VALUE IS: " + options[i].value);
}
}
}
Use forEach to loop through he json..
There are multiple ways of doing it.
This is one of the way
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
},
{
key: "second",
value: "Second Option"
}];
options.forEach(function(item){
console.log(item.value)
})
DEMO
You may want to consider restructuring your data. It appears you took key, value literally:
If you structure your data like this:
var options = [
{
select: null
},
{
one: 'first option'
}
];
You can just call options.select to retrieve the value.
If you don't mind the dependency, you can turn your array into a proper Object using Lodash _.fromPairs:
pairs = options.map(o => [o.key, o.value])
// [["select", null], ["one", "First"], ["two", "Second"]]
_.fromPairs(pairs)
// { select: null, one: "First", second: "Second" }
I hope this will work for you
function getValue(keyName) {
if(!keyName) return ''
var value = _.find(options, function(obj){
if(obj.key === keyName) {
return true
}
})
if(value === undefined) return ''
return value.value
}
var a = getValue('one')
Check snippet for working example.
$(function(){
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
},
{
key: "second",
value: "Second Option"
}];
function getValue(keyName) {
if(!keyName) return ''
var value = _.find(options, function(obj){
if(obj.key === keyName) {
return true
}
})
if(value === undefined) return ''
return value.value
}
var a = getValue('one')
console.log(a)
})
<script src="http://underscorejs.org/underscore.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
For older/ES3 environments:
function find(arr, key) {
for (var i = 0; i < arr.length; i += 1) {
if (arr[i].key === key) {
return arr[i].value;
}
}
}
For newer/ES5 environments:
function find(arr, key) {
return (arr.filter(function(item) { return item.key === key})[0] || {}).value;
}
This is one way of doing it. I have changed the structure of it like other suggested through program and then access the new Structure.
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
},
{
key: "second",
value: "Second Option"
}];
function changeStructure(obj){
var newObj = {};
obj.forEach(function(val, index){
newObj[val['key']] = val['value'];
});
return newObj;
}
var newStructure = changeStructure(options);
New Structure :
{
one : "First Option"
second:"Second Option"
select:null
}
Now you can access it using key:
console.log(newStructure['select']); or console.log(newStructure.select)
JS Fiddle
You can use for..of loop.
var options = [{
key: "select",
value: null
}, {
key: "one",
value: "First Option"
}, {
key: "second",
value: "Second Option"
}];
let filter = (array, prop, res = void 0) => {
for (let {key, value} of array) prop === key && (res = value); return res
}
console.log(filter(options, "select"));
console.log(filter(options, "one"));
console.log(filter(options, "second"));

How to Group By Json Array

I have an array and i want to apply group By column (key).
I have this.
app.groupDtData = function(data, column) {
var generatedData=[];
$.each(data,function(i,dt){
// generatedData
// if(jQuery.inArray( "John", generatedData ))
});
}
i have to push it into generatedData and check by jQuery.inArray ?
You wouldn't use inArray for that as you need an object to hold the result, not an array. Use the in operator to look for the property in the object.
You would get the column value from the item and then check if it exist in the result. If it doesn't exist, add a new array by that name. Add the item to the array and lastly return the result:
app.groupDtData = function(data, column) {
var generatedData = {};
$.each(data, function(i, dt) {
var key = dt[column];
if (!(key in generatedData)) {
generatedData[key] = [];
}
generatedData[key].push(dt);
});
return generatedData;
};
Demo:
function group(data, column) {
var generatedData = {};
$.each(data, function(i, dt) {
var key = dt[column];
if (!(key in generatedData)) {
generatedData[key] = [];
}
generatedData[key].push(dt);
});
return generatedData;
}
var g = group([
{ name: 'John', grp: '1' },
{ name: 'Elsa', grp: '2' },
{ name: 'Mandy', grp: '2' },
{ name: 'Bo', grp: '1' }
], 'grp');
document.write(JSON.stringify(g));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Filter Array based on another array

I have a list with that contains a list of objects. Each object has 4 properties on it. There is a checkbox list with the unique values of two of the properties, this helps build my filter array.
the Filter might end up looking like this:
[
{
prop: 'username',
val: ['max', 'sam']
},
{
prop: 'color',
val: ['blue', 'green']
}
]
The list of objects would look something like this:
[
{
username: 'sam',
color: 'blue'
},
{
username: 'jimmy',
color: 'blue'
},
{
username: 'sam',
color: 'black'
},
{
username: 'max',
color: 'green'
},
{
username: 'max',
color: 'blue'
}
]
The Desired Result
[
{
username: 'sam',
color: 'blue'
},
{
username: 'max',
color: 'green'
},
{
username: 'max',
color: 'blue'
}
]
I feel like I'm going down a never ending forEach rabbit hole. I'm guessing I need some sort of recursion. Currently here is what I have:
var temporary = scope.transactions;
function getFilteredTransactions() {
var filter = deviceFilterService.get();
if (filter.length > 0) {
var temp2 = [];
angular.forEach(filter, function (fil) {
//object
angular.forEach(fil.val, function (filterValue) {
//list on each object
angular.forEach(temporary, function (transaction) {
if (transaction[fil.prop] === filterValue) {
if (temp2.indexOf(transaction) === -1) {
temp2.push(transaction);
}
}
});
temporary = temp2;
});
});
$log.debug(temporary);
scope.transactions = temporary;
} else {
initialize();
}
}
This is starting to work, the second time it goes through the property for color it ends up just wanting to add the exact same transaction to the temp2 array. There has to be a better way to set this up, possibly through recursion.
If you convert the format of the first list to a dictionary, i think if should get easier.
var dict = {};
angular.forEach(source1, function(ob){
dict[ob.prop] = ob.val;
});
function getFiltered(ob){
for(var prop in ob){
if(dict[prop] && dict[prop].indexOf(ob[prop]) === -1){
return false;
}
}
return true;
};
and just call it as:
var temporary = scope.transactions.filter(getFiltered);
Demo
Basically the first part converts:
[
{
prop: 'username',
val: ['max', 'sam']
},
{
prop: 'color',
val: ['blue', 'green']
}
];
to:
{
username:['max', 'sam'],
color:['blue', 'green']
}
so that it makes the look up much easier.
You might want to change the variable names here for clarity, but this will do what you're asking for:
var values = {};
angular.forEach(startingData, function(rawData) {
angular.forEach(rawData, function(value, key) {
if (angular.isUndefined(values[key])) {
values[key] = [];
}
if (values[key].indexOf(value) === -1) {
values[key].push(value);
}
})
});
var result = [];
angular.forEach(values, function(value, key) {
result.push({prop: key, val: value})
});
You can simply iterate each key of the data the needs filtering, find the appropriate filter per that key, and check the value against the filter values:
$scope.transactions = $scope.transactions.filter(isItemValidFilter);
function isItemValidFilter(item) {
var filters = deviceFilterService.get();
//For each property in the data, get the correct filter from the list of filters
var totalConditions = Object.keys(item).length;
var correctConditions = 0;
for (var filterKey in item) {
var correctFilters = filters.filter(function(dataFilter) {
return dataFilter.prop == filterKey
});
if (correctFilters.length) {
//Ill assume only 1 filter, so just use the 0 index
var correctFilter = correctFilters[0];
var conditions = correctFilter.val;
if (conditions && conditions.length) {
//check the values!
if (conditions.indexOf(item[filterKey]) > -1) {
correctConditions++;
}
}
}
}
return correctConditions === totalConditions;
}
Demo: http://jsfiddle.net/Lz32hka5/1/
Try:
var temp2 = [], matched;
angular.forEach(temporary, function(item){
matched = true;
angular.forEach(Object.keys(item), function(key){
angular.forEach(filter, function(filter){
filter.prop == key && filter.val.indexOf(item[key]) == -1 && (matched = false);
});
});
matched && temp2.push(item);
});
console.log(temp2)
temporary is the list of objects, filter: your filters
Demo: http://jsfiddle.net/wZVanG/7wnae850/

Get string representation of JavaScript object

I have a object like so:
$scope.query = {
filter: {
column: {
productName: 'Some Product',
price: 29.95,
...
},
table: {
productType: 'GM',
categoryId: 1,
...
}
}
};
How do I get a string that represents the whole object in dot notation? e.g.
query.filter.table.productType
To clarify, I am using this string value as a key to store a key/value pair in localStorage.
I am using angular to $wacth each property on the object for a change. Since you can't watch an object and know which property changed with watching all, I need to get creative and store each property in a key/value pair.
You can do it recursively, and produces "key" in an array.
var obj = {
query: {
filter: {
table: {
productType: 'GM'
}
}
}
};
var stringify = function (e) {
var rs = [];
for (var k in e) {
if (e.hasOwnProperty(k)) {
if (typeof e[k] == 'object') {
var l = stringify(e[k]);
for (var i = 0; i < l.length; i++) {
rs.push(k + '.' + l[i]);
}
} else {
rs.push(k);
}
}
}
return rs;
}
console.log(stringify(obj));
outputs:
["query.filter.table.productType"]
fiddle
Demo
Before Ques Edit
var $scope = {
query: {
filter: {
table: {
productType: 'GM'
}
}
}
};
var k = JSON.stringify($scope)
//output "{"query":{"filter":{"table":{"productType":"GM"}}}}"
k.match(/\w+(?=\"\:)/g).join('.')
//output"query.filter.table.productType"
Edit
Updated Demo
If OP has no issue with the position of child elements
var $scope = {}
$scope.query = {
filter: {
column: {
productName: 'Some Product',
price: 29.95
},
table: {
productType: 'GM',
categoryId: 1,
}
}
};
k=JSON.stringify($scope)
{"query":{"filter":{"column":{"productName":"Some Product","price":29.95},"table":{"productType":"GM","categoryId":1}}}}
k.match(/\w+(?=\"\:)/g).join('.')
"query.filter.column.productName.price.table.productType.categoryId"
By iterating the properties into an array recursively you could create a hierarchical structure that represents the data in the object. From here you could parse the results out as you wish.
var scope = {
query: {
filter: {
column: {
productName: 'Some Product',
price: 29.95
},
table: {
productType: 'GM',
categoryId: 1
}
}
}
};
function buildProps(subject) {
var result = [];
for (var key in subject) {
if (subject.hasOwnProperty(key)) {
if (typeof subject[key] == "object") {
result.push(key, buildProps(subject[key]));
} else {
result.push(key);
}
}
}
return result;
}
function stringify(input) {
var result = [];
for (var i = 0; i < input.length; i++) {
if (typeof input[i] == "string") {
result.push(input[i]);
} else {
result = result.concat(stringify(input[i]));
}
}
return result.join('.');
}
console.log(buildProps(scope));
console.log(stringify(buildProps(scope)));
Parse out the strings in the resulting array/sub-arrays, format it any way you like.
In my simple example I just list them in order:
query.filter.column.productName.price.table.productType.categoryId

Categories