If I access an array as a property, can I still access its inner indices by saying theArray[index]?
Here's the code I have:
function Dictionary() {
var articles, verbs, nouns, prepositions, adjectives, words;
articles = ["the", "a"];
verbs = ["shoot", "break", "amaze", "grope", "destroy", "bark", "stream", "flow"];
nouns = ["journal", "bird", "library", "book", "calculator", "pen", "evening"];
prepositions = ["while", "although", "beside", "by", "in", "outside", "like", "into"];
adjectives = ["white", "black", "blue", "red", "bright", "calm", "cheerful", "clumsy", "cloudy"];
words = [articles, verbs, nouns, prepositions, adjectives];
Object.defineProperties(this, {
"theWords": {
get: function() {return words;}
},
"theArticles": {
get: function() {return articles;}
},
"theVerbs": {
get: function() {return verbs;}
},
"theNouns": {
get: function() {return nouns;}
},
"thePrepositions": {
get: function() {return prepositions;}
},
"theAdjectives": {
get:function() {return adjectives;}
}
});
}
In another Javascript function called Poem, I want to access Dictionary's property "theWords". I am doing this by saying something like
var theDictionary = new Dictionary();
var articles = theDictionary.theWords[0];
Is this possible? Furthermore, can I access the specific indices inside the array "articles" by saying something like:
var article1 = theDictionary.theWords[0][0];
Is this possible? My code is giving me an error, but I am not sure what is wrong.
This is what I would do:
function Dictionary(user){
/* It's less code to write `var` repeatedly than the variable name twice
in this case. You can save keystrokes, avoid pressing shift, by using
single quotes. That does not mean your code was not clear or didn't work
*/
this.currentUser = user;
this.articles = ['the', 'a'];
this.verbs = ['shoot', 'break', 'amaze', 'grope', 'destroy', 'bark', 'stream', 'flow'];
this.nouns = ['journal', 'bird', 'library', 'book', 'calculator', 'open', 'evening'];
this.prepositions = ['while', 'although', 'beside', 'by', 'in', 'outside', 'like', 'into'];
this.adjectives = ['white', 'black', 'blue', 'red', 'bright', 'calm', 'cheerful', 'clumsy', 'cloudy'];
this.words = [this.articles, this.verbs, this.nouns, this.prepositions, this.adjectives];
// you don't really need this function - just an example of a Constructor function
this.wordsToString = function(){
var wds = this.words, a = [];
for(var i in wds){
a.concat(wds[i])
}
return a.join();
}
}
var dic = new Dictionary('Bob');
console.log(dic.currentUser); console.log(dic.articles[0]);
console.log(dic.wordsToString());
Now you can change the articles property, or whatever:
dic.articles = ['test1', 'test2'];
console.log(dic.wordsToString());
Related
I have an array of objects and I'm wondering the best way to search it. Given the below example how can I search for name = "Joe" and age < 30? Is there anything jQuery can help with or do I have to brute force this search myself?
var names = new Array();
var object = { name : "Joe", age:20, email: "joe#hotmail.com"};
names.push(object);
object = { name : "Mike", age:50, email: "mike#hotmail.com"};
names.push(object);
object = { name : "Joe", age:45, email: "mike#hotmail.com"};
names.push(object);
A modern solution with Array.prototype.filter():
const found_names = names.filter(v => v.name === "Joe" && v.age < 30);
Or if you still use jQuery, you may use jQuery.grep():
var found_names = $.grep(names, function(v) {
return v.name === "Joe" && v.age < 30;
});
You can do this very easily with the [].filter method:
var filterednames = names.filter(function(obj) {
return (obj.name === "Joe") && (obj.age < 30);
});
You can learn more about it on this MDN page.
You could utilize jQuery.filter() function to return elements from a subset of the matching elements.
var names = [
{ name : "Joe", age:20, email: "joe#hotmail.com"},
{ name : "Mike", age:50, email: "mike#hotmail.com"},
{ name : "Joe", age:45, email: "mike#hotmail.com"}
];
var filteredNames = $(names).filter(function( idx ) {
return names[idx].name === "Joe" && names[idx].age < 30;
});
$(filteredNames).each(function(){
$('#output').append(this.name);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"/>
var nameList = [
{name:'x', age:20, email:'x#email.com'},
{name:'y', age:60, email:'y#email.com'},
{name:'Joe', age:22, email:'joe#email.com'},
{name:'Abc', age:40, email:'abc#email.com'}
];
var filteredValue = nameList.filter(function (item) {
return item.name == "Joe" && item.age < 30;
});
//To See Output Result as Array
console.log(JSON.stringify(filteredValue));
You can simply use javascript :)
For those who want to filter from an array of objects using any key:
function filterItems(items, searchVal) {
return items.filter((item) => Object.values(item).includes(searchVal));
}
let data = [
{ "name": "apple", "type": "fruit", "id": 123234 },
{ "name": "cat", "type": "animal", "id": 98989 },
{ "name": "something", "type": "other", "id": 656565 }]
console.log("Filtered by name: ", filterItems(data, "apple"));
console.log("Filtered by type: ", filterItems(data, "animal"));
console.log("Filtered by id: ", filterItems(data, 656565));
filter from an array of the JSON objects:**
var names = [{
name: "Joe",
age: 20,
email: "joe#hotmail.com"
},
{
name: "Mike",
age: 50,
email: "mike#hotmail.com"
},
{
name: "Joe",
age: 45,
email: "mike#hotmail.com"
}
];
const res = _.filter(names, (name) => {
return name.name == "Joe" && name.age < 30;
});
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
So quick question. What if you have two arrays of objects and you would like to 'align' these object arrays so that you can make sure each array's objects are in the order as the other array's? What if you don't know what keys and values any of the objects inside of the arrays contains... Much less what order they're even in?
So you need a 'WildCard Expression' for your [].filter, [].map, etc. How do you get a wild card expression?
var jux = (function(){
'use strict';
function wildExp(obj){
var keysCrude = Object.keys(obj),
keysA = ('a["' + keysCrude.join('"], a["') + '"]').split(', '),
keysB = ('b["' + keysCrude.join('"], b["') + '"]').split(', '),
keys = [].concat(keysA, keysB)
.sort(function(a, b){ return a.substring(1, a.length) > b.substring(1, b.length); });
var exp = keys.join('').split(']b').join('] > b').split(']a').join('] || a');
return exp;
}
return {
sort: wildExp
};
})();
var sortKeys = {
k: 'v',
key: 'val',
n: 'p',
name: 'param'
};
var objArray = [
{
k: 'z',
key: 'g',
n: 'a',
name: 'b'
},
{
k: 'y',
key: 'h',
n: 'b',
name: 't'
},
{
k: 'x',
key: 'o',
n: 'a',
name: 'c'
}
];
var exp = jux.sort(sortKeys);
console.log('#juxSort Expression:', exp);
console.log('#juxSort:', objArray.sort(function(a, b){
return eval(exp);
}));
You can also use this function over an iteration for each object to create a better collective expression for all of the keys in each of your objects, and then filter your array that way.
This is a small snippet from the API Juxtapose which I have almost complete, which does this, object equality with exemptions, object unities, and array condensation. If these are things you need or want for your project please comment and I'll make the lib accessible sooner than later.
Hope this helps! Happy coding :)
The most straightforward and readable approach will be the usage of native javascript filter method.
Native javaScript filter takes a declarative approach in filtering array elements. Since it is a method defined on Array.prototype, it iterates on a provided array and invokes a callback on it. This callback, which acts as our filtering function, takes three parameters:
element — the current item in the array being iterated over
index — the index or location of the current element in the array that is being iterated over
array — the original array that the filter method was applied on
Let’s use this filter method in an example. Note that the filter can be applied on any sort of array. In this example, we are going to filter an array of objects based on an object property.
An example of filtering an array of objects based on object properties could look something like this:
// Please do not hate me for bashing on pizza and burgers.
// and FYI, I totally made up the healthMetric param :)
let foods = [
{ type: "pizza", healthMetric: 25 },
{ type: "burger", healthMetric: 10 },
{ type: "salad", healthMetric: 60 },
{ type: "apple", healthMetric: 82 }
];
let isHealthy = food => food.healthMetric >= 50;
const result = foods.filter(isHealthy);
console.log(result.map(food => food.type));
// Result: ['salad', 'apple']
To learn more about filtering arrays in functions and yo build your own filtering, check out this article:
https://medium.com/better-programming/build-your-own-filter-e88ba0dcbfae
If i've two array like
a= [{ name: 'a', name: 'b' }]
b= [c, d, b, e]
I want the result to be like
[
{ 'name': 'a' },
{ 'name': 'b' },
{ 'name': 'c' },
{ 'name': 'd' },
{ 'name': 'e' }
]
But do not want to repeatedly check like first array convert using _.map() and after merge using _.union() or other type then check _.uniq() through but I need all if possible then make as a short layer.
To do this with Backbone.Collection, you can leverage the model parse function as well as providing the parse: true option on instantiation. By specifying a model idAttribute, duplicate models are avoided. Note: I used lodash here for some type checking and array merge.
var a = [{name: 'a'}, {name: 'b'}];
var b = ['c', 'd', 'b', 'e'];
var Coll = Backbone.Collection.extend({
model: Backbone.Model.extend({
idAttribute: 'name',
parse: function(resp, opts) {
var modelData = resp;
if (_.isString(resp)) {
modelData = { name: resp };
}
return modelData;
}
})
});
// then on initialize
var data = _.union(a, b);
var coll = new Coll(data, {parse: true});
console.log(JSON.stringify(coll.toJSON()));
// yields
"[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"},{"name":"e"}]"
// alternatively, you can choose not merge the data to start
// and instead either pass some at initialize and then
// some with a coll.set later, or all with set
// Note: set call still needs parse:true as well as remove:false
var coll = new Coll(a, {parse: true});
coll.set(b, {parse: true, remove: false});
console.log(JSON.stringify(coll.toJSON()));
// yields
"[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"},{"name":"e"}]"
I have this array and variable:
var freqId = 45;
$scope.frequencies = [{Id:124,name:'qqq'},
{Id:589,name:'www'},
{Id:45,name:'eee'},
{Id:567,name:'rrr'}]
I use this row to get all id's from array above:
var inspectionsId = $scope.frequencies.map(function (obj) { return obj.Id; })
The result I get is:
var Id's = [124,589,45,567];
I need to change this row:
$scope.frequencies.map(function (obj) { return obj.Id; })
to retrive all id from frequencies array except where Id equal to freqId variable.
For example desired result is:
var inspectionsId = [124,589,567];
Any idea how can I implemet it?
You can also use Array.prototype.reduce to do both filtering and mapping in a single loop:
var freqId = 45;
$scope = {}; // Dummy scope
$scope.frequencies = [{
Id: 124,
name: 'qqq'
}, {
Id: 589,
name: 'www'
}, {
Id: 45,
name: 'eee'
}, {
Id: 567,
name: 'rrr'
}]
var result = $scope.frequencies.reduce(function(result, current) {
if (current.Id != freqId) {
result.push(current.Id);
}
return result;
}, []);
console.log(JSON.stringify(result));
map is designed to transform data, not filter it. Chain it with filter for the latter.
var freqId = 45;
var input = [{
Id: 124,
name: 'qqq'
}, {
Id: 589,
name: 'www'
}, {
Id: 45,
name: 'eee'
}, {
Id: 567,
name: 'rrr'
}];
var output = input.map(function(obj) {
return obj.Id;
}).filter(function(element) {
return element != freqId
});
console.log(output);
You can use Array.prototype.filter:
var inspectionsId = $scope.frequencies
.map(function(obj) { return obj.Id; })
.filter(function(id) { return id !== 45 })
You'll have seen the filter answers. 99.999% of the time, that's the way to go.
If you have a truly massive array and you think it's important to make just a single pass through it, you could give yourself a function combining map and filter:
// A value to use to mean "leave entry out"
Object.defineProperty(Array.prototype, "OMIT", {
value: {}
});
// The utility function
Object.defineProperty(Array.prototype, "mapFilter", {
value: function(f, thisArg, omissionFlag) {
var result = [];
if (arguments.length < 3) {
omissionFlag = Array.OMIT;
}
Object.keys(this).forEach(function(index) {
var value = f.call(thisArg, this[index], index, this);
if (value !== omissionFlag) {
result.push(value);
}
}, this);
return result;
}
});
// Using it
var freqId = 45;
var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567, name: 'rrr'}];
var output = input.mapFilter(function(obj) {
return obj.Id == freqId ? Array.OMIT : obj.Id;
});
console.log(output);
This version accepts up to three arguments:
The map/filter function
The value to use as this during callbacks
The value to use to mean "omit this entry," which defaults to Array.OMIT
It calls its callback with the value, index, and array just like forEach and map and such do.
Again, though, I'll emphasize that in the vast, vast majority of cases, filter and then map (or map and then filter if the map makes filtering easier) is the way to go.
That said, a generic "loop with memo" function has broader applicability:
// The utility function
Object.defineProperty(Array.prototype, "memoLoop", {
value: function(memo, f, thisArg) {
Object.keys(this).forEach(function(index) {
f.call(thisArg, memo, this[index], index, this);
}, this);
return memo;
}
});
// Using it
var freqId = 45;
var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567, name: 'rrr'}];
var output = input.memoLoop([], function(result, obj) {
var id = obj.Id;
if (id != freqId) {
result.push(id);
}
});
console.log(output);
It's a bit like Array#reduce but assumes an unchanging memo value (in our case, the new array), which simplifies the callback somewhat.
var set = [{"color":"blue"},{"color":"green"},{"color":"red"},{"color":"green"}];
I'd like to be able to do something like a db call, set.find({"color":"green"}) and have it return an array full of objects that contain that property.
Using Array#filter, for this particular case the code would look like
var results = set.filter(function (entry) { return entry.color === "green"; });
Array#filter is not implemented in some older browsers, so see the linked article for a backward compatibility shim, or better yet get a full-fledged ES5 shim.
For the more general case, it's just a matter of extending this idea:
function findByMatchingProperties(set, properties) {
return set.filter(function (entry) {
return Object.keys(properties).every(function (key) {
return entry[key] === properties[key];
});
});
}
var results = findByMatchingProperties(set, { color: "green" });
Again, I am using ECMAScript 5 methods Object.keys and Array#every, so use an ES5 shim. (The code is doable without an ES5 shim but uses manual loops and is much less fun to write and read.)
I have used map function from jquery and I am getting selected index by passing searched key value so by using that index we will get required object from array.
var mydata = [{ name: "Ram", Id: 1 }, { name: "Shyam", Id: 2 }, { name: "Akhil", Id: 3 }];
searchKey = 2
var mydata = [{ name: "Ram", Id: 1 }, { name: "Shyam", Id: 2 }, { name: "Akhil", Id: 3 }];
searchKey = 2
var selectedData = mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey)];
console.log(selectedData)
var selectedData = mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey)];
console.log(selectedData)
output
{ name: "Shyam", Id: 2 }
Note: if you want to pass search key as object then
searchKey = { Id: 2 };
mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey.Id)];
output
{ name: "Shyam", Id: 2 }
Using arrow functions with an implied return and concise body:
const results = set.filter(entry => entry.color === "green");
Another example passing in a search variable:
const searchString = 'green';
const results = set.filter(entry => entry.color === `${searchString}`);
Read more about arrow functions on
MDN
Since you've included the jQuery tag, here's one way to do it using jQuery's map:
var results = $.map( set, function(e,i){
if( e.color === 'green' ) return e;
});
The documentation states that you need to return null to remove the element from the array, but apparently this is false, as shown by the jsFiddle in the comments; returning nothing (i.e. returning undefined) works just as well.
I went with a different approach that I found to be a bit easier.
function isObjEqual(a, b) {
const x = JSON.stringify(a);
const y = JSON.stringify(b);
return x === y;
}
// Example 1
const set = [{"color":"blue"},{"color":"green"},{"color":"red"},{"color":"green"}];
const findObj1 = {"color":"green"};
const arr1 = set.filter((objInArr) => isObjEqual(objInArr, findObj1));
console.log(arr1) // [ { color: 'green' }, { color: 'green' } ]
// Example 2
const list = [{
"label": "Option 2",
"value": "option2"
},
{
"label": "Option 3",
"value": "option3"
},
{
"label": "Option 2",
"value": "option2"
}
];
const findObj2 = {
"label": "Option 2",
"value": "option2"
}
const newList = list.filter((objInArr) => isObjEqual(objInArr, findObj2));
console.log(newList) //[ { label: 'Option 2', value: 'option2' }, { label: 'Option 2', value: 'option2' } ]
Is there a way to specify common elements for object literals in an array?
For example:
var array = [ {key: "hi", label: "Hi", formatter:deleteCheckboxFormatter},
{key: "hello", label: "Hello", formatter:deleteCheckboxFormatter},
{key: "wut", label: "What?", formatter:deleteCheckboxFormatter}];
All three records use the same formatter. How would you refactor this?
A pair of alternatives come to my mind:
A helper function with the default value for the common field:
function make(key, label) {
return {'key': key, 'label': label, formatter:deleteCheckboxFormatter};
}
var array = [ make("hi", "Hi"),
make("hello", "Hello"),
make("wut", "What?")];
Or a more generic function that accepts an argument for the formatter property:
function make (formatter) {
return function (key, label) {
return {'key': key, 'label': label, 'formatter':formatter};
}
}
// a function to build objects that will have a 'fooFormatter'
var foo = make('fooFormatter');
var array = [ foo ("hi", "Hi"),
foo ("hello", "Hello"),
foo ("wut", "What?")];
And the last thing that comes to my mind is simply iterate over the array assigning the common field:
var array = [ {key: "hi", label: "Hi"},
{key: "hello", label: "Hello"},
{key: "wut", label: "What?"}];
var i = array.length;
while (i--) {
array[i].formatter = 'deleteCheckboxFormatter';
}
I used here a while loop in reverse order, because the order of iteration is not important and this type of loop performs better.
var array = [ {key: "hi", label: "Hi"},
{key: "hello", label: "Hello"},
{key: "wut", label: "What?"}];
for(var item in array)
item["formatter"] = deleteCheckboxFormatter;
You could make an object out of it using a constructor:
function Obj(key, label){
this.key = key;
this.label = label;
this.formatter = "deleteCheckboxFormatter";
}
var array = [ new Obj("hi", "Hi"),
new Obj("hello", "Hello"),
new Obj("wut", "What?") ];