How do I slice an array from an array of object literals? - javascript

I have this array, in which each index contains an object literal. All of the object literals have the same properties. Some of the object literals have the same value for a given property, and I want to create a new array containing only those object literals.
My idea is to sort the array, and slice it into a new array...
Here is the array:
var arr = [];
arr[0] =
{
country: "United States",
num: 27
};
arr[1] =
{
country: "Australia",
num: 5
};
arr[2] =
{
country: "United States",
num: 7
};
So, I want to create a new array containing only those objects where the property country is "United States". This is my crazy idea so far, which doesn't work:
function getNewArray(arr)
{
var arr2 = [];
for(var key in arr)
{
for(var i = 0; i < arr.length - 1; i++)
{
if(arr.hasOwnProperty(key) && arr[i].name == arr[i + 1].name)
{
arr2[i] = arr.slice(key);
}
}
}
return arr2;
}
var arr3 = getNewArray(arr).sort();

"I want to create a new array containing only those objects where the property country is "United States""
This is exactly what the Array.filter() method is for:
var filteredArray = arr.filter(function(val, i, a) {
return val.country==="United States";
});
Note that the .filter() method isn't available in IE before version 9, but the MDN page I linked to above shows you exactly how to implement it so reading that page should in itself answer your question.
Note also that in the (non-working) code in the question, your two for loops are basically doing the same thing as each other because they're both iterating over arr, so it doesn't make sense to nest them like that. You shouldn't use a for..in loop on an array, but if you do the key values will be the numeric indexes, it doesn't somehow pick up the properties of the object stored at each index.
EDIT:
"Some of the object literals have the same value for a given property, and I want to create a new array containing only those object literals."
OK, re-reading this I guess you didn't really want to select elements by specifying a country, you wanted to select elements for any country that had duplicate entries? So if there were another three elements that all had "New Zealand" you'd want to select them in addition to the "United States" ones? If so, you could do something like this:
var countryCount = {},
i;
for (i = 0; i < arr.length; i++)
if (countryCount.hasOwnProperty(arr[i].country)
countryCount[arr[i].country]++;
else
countryCount[arr[i].country] = 1;
var filteredArr = arr.filter(function(val, i, a) {
return countryCount[val.country] > 1;
});

var getCountry = function (country) {
var out = [];
for (var i = 0, len = arr.length; i < len; i++)
if (arr[i].country === country) out.push(arr[i]);
return out;
};
Demo: http://jsfiddle.net/YwytD/1/

There is a simpler way of doing this, I think this is what you want
var new_arr = arr.filter(function(obj){ return obj['country'] === 'United States'; })
This will filter your results into new_arr
Of course you can make it better and more generic than just 'United States'
Edit:
Whoops, got your question just now
Answer: Nested Filters :)
function getKeyStuff(key) {
return arr.filter( function(obj) {
var new_arr = arr.filter( function(inner_obj) {
return inner_obj[key] === obj[key];
});
return new_arr.length > 1;
});
}

Here is my solution:
// assuming arr is already set
var num_obj = arr.length;
var obj_by_country = {}, obj;
for (var i = 0; i < num_obj; i++) {
obj = arr[i];
if (!obj_by_country[obj.country]) {
obj_by_country[obj.country] = [];
}
obj_by_country[obj.country].push(obj);
}
// build final array
var final_array = [];
for (i in obj_by_country) {
if (obj_by_country[i].length > 1) {
final_array.push(obj_by_country[i]);
}
}

Can you use JQuery?
var arr = [];
arr[0] = { country: "United States", num: 27 };
arr[1] = { country: "Australia", num: 5 };
arr[2] = { country: "United States", num: 7 };
var newArray = [];
$.each(arr, function(){
if(this.country == "United States")
newArray.push(this);
});

getByKey = function(arr, key, value) {
var results = [];
for(var i = 0; i < arr.length; i++) {
if(arr[i][key] === value) {
results.push(arr[i]);
}
}
return results
}
here's a working example
http://jsfiddle.net/michaelghayes/UyHYz/2/

Related

Modify an object to a new Array in Javascript

sorry, i m a beginner in javascript.
Can someone explain me how to modify this Object
{toto:[12,13,15],titi:[45,12,34]}
to this Array
newArray = [
{
toto:12,
titi:45
},{
toto:13,
titi:12
},{
toto:15,
titi:34}
]
Also, what the solution if the toto and titi doesn't have the same lenght
Thanks for support!
Here's how I did it. In this way, you don't need to know the names of the keys or the size of the array, but it does require a few loops.
obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
// Find the longest array in your data set
longest = 0;
Object.keys(obj).forEach(function(key) {
if (obj[key].length > longest) {
longest = obj[key].length;
}
});
// Loop through the existing data set to create new objects
for (i = 0; i<longest; i++) {
newObject = {};
Object.keys(obj).forEach(function(key) {
newObject[key] = obj[key][i];
});
newArray.push(newObject);
}
console.log(newArray);
plnkr.co demo in the script.js file.
If you want to ignore keys that would have undefined values for uneven loops, you can add a conditional inside the forEach loop that creates a new object:
Object.keys(obj).forEach(function(key) {
if (obj[key][i] !== undefined) {
newObject[key] = obj[key][i];
}
});
Assuming lengths of toto and titi are the same:
Obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
for (var k in Obj["toto"]) {
newArray.push({ toto:Obj["toto"][k],titi:Obj["titi"][k] });
}
Since the lengths of your inner arrays are equal, you should be able to simply loop through them and add a value from each array (for each iteration) into a new array :
// Your input
var input = {toto:[12,13,15],titi:[45,12,34]};
// An array to store your output
var output = [];
// Since your inner arrays are of equal size, you can loop through them
// as follows
for(var i = 0; i < input.toto.length; i++){
output.push({ toto: input.toto[i], titi: input.titi[i]});
}
You can see a working example of this here and what the output array looks like below :
A more generic approach
var object = { toto: [12, 13, 15], titi: [45, 12, 34] },
newArray = function (o) {
var keys = Object.keys(o),
l = keys.reduce(function (r, a) { return Math.max(r, o[a].length); }, 0),
i = 0,
t,
result = [];
while (i < l) {
t = {};
keys.forEach(function (k) { t[k] = o[k][i]; });
result.push(t);
i++;
}
return result;
}(object);
document.write('<pre>' + JSON.stringify(newArray, 0, 4) + '</pre>');

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>

How to check if array is unique on specific object property?

I have an array of objects:
var array1 = [
{
property1: 10,
property2: "abc"
},
{
property1: 11,
property2: "def"
},
{
property1: 10,
property2: "ghi"
}
];
Now what I want is this array will be said not unique as per value of property1.
This means that this array contains 2 elements with property1=10, so the array does not contain unique value of property1.
To check this, I can use a for loop:
for (var i = 0; i < array1.length; i++) {
var array2 = array1.slice(); // copy array
array2.remove(array1[i]);
var temppropety1 = array1[i].property1;
for (var j = 0; j < array2.length; j++) {
if (array2[J].property1==temppropety1) {
return true;
}
}
}
But is there an easier way or a library to find this?
Here is a straightforward way to test for uniqueness on property1. Loop through the objects in the outer array and add each object's property1 to a temp array if it is not already in that temp array. If a duplicate value is encountered, return false meaning property1 is not unique.
function isUnique(arr) {
var tmpArr = [];
for(var obj in arr) {
if(tmpArr.indexOf(arr[obj].property1) < 0){
tmpArr.push(arr[obj].property1);
} else {
return false; // Duplicate value for property1 found
}
}
return true; // No duplicate values found for property1
}
Demo: http://jsbin.com/lohiqihipe/1/
First, you could reduce (aggregate) the objects by grouping them by the value of property1:
var grouped = array.reduce(function(grouped, item) {
var propertyValue = item.property1;
grouped[propertyValue] = (grouped[propertyValue] || 0) + 1;
return grouped;
}, {});
Then you check that every key of the resulting object has a value of 1:
var result = Object.keys(grouped).every(function(key) {
return grouped[key] === 1;
});
I suggest that array can be quite big so I'd prefer not to copy it and just validate properties.
Also it is not an option to use map function of array because in this case you won't be able to break a cycle on first match:
var equals = function(array) {
var co = {};
var unique = true;
for(var i = 0; i < array.length; i++) {
var o = array[i];
if (co[o.property1]) {
unique = false;
break;
} else {
co[o.property1] = true;
}
}
return unique;
};
You can convert your array to flat structure:
array1.map(function(item) { return item.property1; });
and now your problem simplify to check duplicates in simple array
var array1 = ["a","b","b","c","d","e","f"];
var uniqueItems = [];
$.each(array1, function(i, el){
if($.inArray(el, uniqueItems) === -1) uniqueItems.push(el);
});
References:
https://stackoverflow.com/a/840808/4772988
https://stackoverflow.com/a/9229932/4772988
You can use a couple of helpers to abstract it:
var uniqBy = function(f, xs) {
var seen = []
return xs.filter(function(x) {
var fx = f(x)
if (seen.indexOf(fx) > -1) return
seen.push(fx)
return true
})
}
var dot = function(k) {
return function(obj) {
return obj[k]
}
}
Then filter out duplicates by the property, and compare the length of the result to the original array. If they don't match, then they must not be unique:
var res = uniqBy(dot('property1'), array1)
var isUnique = array1.length === res.length
console.log(isUnique) // false
If you got only numbers or only strings to remove duplicates from, then you can improve performance by using an object instead of an array to keep track of elements seen so far.
You can use lodash library to achieve this.
Here is the library documentation: https://lodash.com/docs/4.17.5#filter
Method:-
function isDuplicatesPresent(list, propertyName){
return _.filter(list, function (value) {
return _.filter(list, function(innerValue){ reutrn innerValue[propertyName] === value[propertyName]}).length > 1;
}).length > 0;
}
Example:-
var users = [
{ user: 'barney', age: 36, active: true },
{ user: 'fred', age: 40, active: false },
{ user: 'barney', age: 37, active: true}
];
let duplicates = _.filter(users, function (value) {
return _.filter(users, {user:value.user}).length > 1;
});
Result:
console.log(duplicates)
> [
{"user": "barney","age": 36,"active": true},
{"user": "barney","age": 37,"active": true}
];

Comparing an Array with an Objects' Array in JavaScript

I am new to JavaScript and wondering how can I compare an array with another array consists of JavaScript objects.
The array is a series of sorted time in the "YYYY-MM-DD" format.
The array of objects missed some price values of several days.
I want to find the missed value and assign it as "NULL".
For example, I have an array as:
array = ['2014-10-09','2014-10-10','2014-10-11','2014-10-12'];
and an array with objects as:
objArray = [{
date:"2014-10-09",
price:"100"
},
{
date:"2014-10-10",
price:"99"
},
{
date:"2014-10-12",
price:"102"
}];
I want to get the price array in this way:
priceResult = [100, 99, "NULL", 102];
What would be the most efficient way without using other libraries? I wanted to see if anyone had a more elegant solution. I deeply appreciate your help.
You can create a lookup set from the object array, then you can use that to translate the dates to prices.
This scales well, as it is an O(n+m) solution rather than the O(n*m) solution that you get if you use a loop in a loop to find the prices.
var array = ['2014-10-09','2014-10-10','2014-10-11','2014-10-12'];
var objArray = [{ date:"2014-10-09", model:"A", price:"100" },{ date:"2014-10-10", model:"A", price:"99" },{ date:"2014-10-12", model:"A", price:"102" }];
var lookup = {};
for (var i = 0; i < objArray.length; i++) {
lookup[objArray[i].date] = parseInt(objArray[i].price, 10);
}
var priceResult = [];
for (var i = 0; i < array.length; i++) {
if (lookup.hasOwnProperty(array[i])) {
priceResult.push(lookup[array[i]]);
} else {
priceResult.push('NULL');
}
}
// output result in StackOverflow snippet
document.write(JSON.stringify(priceResult));
Note: Instead of the string 'NULL' you might want to use the value null instead, as it is generally easier to handle.
lodash is the best library for this. But you did say "without using other libraries", so you will need to do it natively.
The easiest way to do it is nested for loops:
var i, j, d, res = [];
for (i=0; i<dateArray.length; i++) {
d = dateArray[i];
for (j=0; j<objArray.length; j++) {
if (objArray[j] && objArray[j].date && objArray[j].date === d) {
res.push(objArray[j].price);
j = objArray.length; // don't waste energy searching any more, since we found it
}
}
}
// res now contains all you wanted
If objArray is really big, and you don't want to search it multiple times, then you could turn it into an object indexed by date:
var i, obj = {}, d, res = [];
for (i=0; i<objArray.length; i++) {
if (objArray[i] && objArray[i].date) {
obj[objArray[i].date] = objArray[i];
}
}
for (i=0; i<dateArray.length; i++) {
d = dateArray[i];
res.push(obj[d] ? obj[d].price : null : null);
}
// res now contains all you wanted
Loop trough the object and search for the date in your array
// Add contains to array proto: http://css-tricks.com/snippets/javascript/javascript-array-contains/
var priceResult = [];
for(var i in objArray) {
if(dateArray.contains(objArray[i].date)) priceResult.push(objArray[i].date));
}
console.log('matches:', priceResult);
This function will give you map of all individual arrays in your object array
function getArrayMap(array) {
var map={}
for(var i=0;i<array.length;i++){
var o = array[i];
for(var k in o){
if(!map[k]){
map[k]=[];
}
map[k].push(o[k]);
}
}
return map;
}
you can use it like -
var map = getArrayMap(objArray);
console.log(map["date"]);//date array
console.log(map["price"]);//price array
console.log(map["model"]);//model array
If i am understanding your question correctly, for all the values in array, you want to check the objArr and find the price for each date, and if not found u want to inset null. If this is what you want, then following will help
var found= false;
var list=[];
for(var i=0; i< dateArray.length; i++)
{
for(var j=0; j< objArray.length; j++)
{
if(objArray[j].date == dateArray[i])
{
list.push(objArray[j].price);
found = true;
}
}
if(!found)
{
list.push("null");
}
found = false;
}
alert(list);
(I'm going to call your first array dates rather than array, to avoid confusion.)
There are basically two options:
Loop through your dates array and, for each entry, loop through the objArray looking for a match, and when found add to your priceResult array, or
Build a map from your objArray, then loop through yourdatesarray once, building thepriceResult` array.
Looping and Looping
You can loop through your dates array using forEach, and you can use Array#some to find out whether your objArray contains the date and add to priceResult if so (it's an ES5 feature, but you can polyfill it for really old browsers):
var priceResult = [];
dates.forEach(function(date) {
objArray.some(function(object) {
if (object.date == date) {
priceResult.push(object.price);
return true;
}
});
});
Array#some keeps looping until you return true, which is why we do that when we find the firs tmatch. That's why I say this is "looping and looping," even though we only write one loop, the other is within Array#some.
var dates = ['2014-10-09', '2014-10-10', '2014-10-11', '2014-10-12'];
var objArray = [
{
date: "2014-10-09",
model: "A",
price: "100"
},
{
date: "2014-10-10",
model: "A",
price: "99"
},
{
date: "2014-10-12",
model: "A",
price: "102"
}
];
// Do it
var priceResult = [];
dates.forEach(function(date) {
objArray.some(function(object) {
if (object.date == date) {
priceResult.push(object.price);
return true;
}
});
});
snippet.log(priceResult.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Mapping and Looping
First, create a map of prices by date:
var prices = {};
objArray.forEach(function(object) {
prices[object.date] = object.price;
});
...then create your results:
var priceResult = [];
dates.forEach(function(date) {
if (prices.hasOwnProperty(date)) {
priceResult.push(prices[date]);
}
});
var dates = ['2014-10-09', '2014-10-10', '2014-10-11', '2014-10-12'];
var objArray = [
{
date: "2014-10-09",
model: "A",
price: "100"
},
{
date: "2014-10-10",
model: "A",
price: "99"
},
{
date: "2014-10-12",
model: "A",
price: "102"
}
];
// Create the map
var prices = {};
objArray.forEach(function(object) {
prices[object.date] = object.price;
});
// Create your results:
var priceResult = [];
dates.forEach(function(date) {
if (prices.hasOwnProperty(date)) {
priceResult.push(prices[date]);
}
});
// Show them
snippet.log(priceResult.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
var dates = ['2014-10-09','2014-10-10','2014-10-11','2014-10-12'];
var objArray = [{date:"2014-10-09", model:"A", price:"100" }, {date:"2014-10-10", model:"A", price:"99" }, {date:"2014-10-12", model:"A", price:"102" }];
var val;
var priceResult = [];
for (var a in dates) {
val = null;
for (var b in objArray) {
if (dates[a] == objArray[b].date) {
val = objArray[b].price;
}
}
priceResult.push(val);
}
var dates = ['2014-10-09', '2014-10-10', '2014-10-11', '2014-10-12'];
var objArray = [{
date: "2014-10-09",
model: "A",
price: "100"
}, {
date: "2014-10-10",
model: "A",
price: "99"
}, {
date: "2014-10-12",
model: "A",
price: "102"
}];
var val;
var priceResult = [];
for (var a in dates) {
val = null;
for (var b in objArray) {
if (dates[a] == objArray[b].date) {
val = objArray[b].price;
}
}
priceResult.push(val);
}
// output result in StackOverflow snippet
document.write(JSON.stringify(priceResult));
Try this:
var temp[]
temp= jQuery.grep(objArray , function (n, i)
{
for(j=0;j<dateArray.lenght+j++ )
if( n.date === dateArray[j])
return n.price;
);
dateArray = ["2014-10-09", "2014-10-10", "2014-10-11", "2014-10-12"];
function ObjectExample(date1,model,price)
{
this.date1 = date1;
this.model = model;
this.price = price;
}
var objArray = [new ObjectExample("2014-10-09","A","100"), new ObjectExample("2014-10-10","A","99"), new ObjectExample("2014-10-12","A","102")];
var i = 0;
var priceDate = new Array();
var count = 0;
while(i < dateArray.length)
{
var j = 0;
while(j < objArray.length)
{
if(dateArray[i] == objArray[j].date1)
{
priceDate[count] = objArray[j].price;
break;
}
else priceDate[count] = "NULL";
j = j + 1;
}
i = i + 1;
count++;
}
document.write(priceDate);

Convert array to object with saving original index field

I have an array that is sorted in the following way
var items = [2.99, 5.99, 23.99, 1.99];
items.sort(function(a,b) { return a - b;});
This outputs the following:
[1.99, 2.99, 5.99, 23.99]
But I need a way to sort it but keep an index of the original index, e.g.
[3: 1.99, 0: 2.99, 1: 5.99, 2:23.99]
Any help would be appreciated.
Map it to an array of objects.
So in the resulting array, each member is an object with an n property that holds the number, and an i property that holds the original index.
You can then iterate that array and get the data like normal.
var items = [2.99, 5.99, 23.99, 1.99];
var arr_of_objs = items.map(function(n, i) {
return { n:n, i:i };
}).sort(function(a, b) {
return a.n - b.n;
});
arr_of_objs.forEach(function(obj, i) {
this.textContent += "number: " + obj.n + ", orig idx: " + obj.i + ", new idx: " + i + "\n";
}, document.querySelector("pre"));
<pre></pre>
var items = [2.99, 5.99, 23.99, 1.99];
var sortable = [];
for (var i = 0; i < items.length; i++) {
sortable.push([i, items[i]]);
}
sortable.sort(function(a, b) {
return a[1] - b[1]
});
console.log(sortable);
Unfortunately it is not possible in JS get sorting in this case. JS understands array only as [0: 1.99, 1:2.99, 3:23.99] -- you cannot change order of indexes. But you can use array of arrays or array of object to solve the problem.
var items = [2.99, 5.99, 23.99, 1.99];
function PreserveKeysSorting(arr) {
var arr = arr
obj = [];
for(i in arr) {
obj.push({index: i, value: arr[i]});
}
obj.sort(function(a,b) { return a.value - b.value;});
return obj;
}
console.log(items);
console.log(PreserveKeysSorting(items));
Live Demo -- http://jsfiddle.net/u1g0xsap/1/
The array that you want as a result is not valid, but you can do something like this:
First make an array that contains objects that persists the index:
var itemsObj = [];
items.forEach(function(value, index) {
itemsObj.push({
value: value,
index: index
});
});
Then you can sort them like this:
items.sort(function(a,b) { return a.value - b.value;});
and you will get an arary of objects like this
[{index:3, value: 1.99}, {index: 0, value: 2.99}, {index: 1, value: 5.99}, {index:2, value:23.99}]
Hardcode the index into the array:
var items = [2.99, 5.99, 23.99, 1.99]
var itemsWithIndex = [];
for (i=0; i<items.length; i++) { itemsWithIndex[i] = [i+1, items[i]]; }
itemsWithIndex.sort(function(a,b) { return a[1]-b[1]; });
Note that an auxiliary variable (itemsWithIndex) was added for clarity, but you can also just update the original array:
var items = [2.99, 5.99, 23.99, 1.99]
for (i=0; i<items.length; i++) { items[i] = [i+1, items[i]]; }
items.sort(function(a,b) { return a[1]-b[1]; });
You could use two arrays and indexOf() method:
// Variables
var items = items_sort = [2.99, 5.99, 23.99, 1.99];
var order = new Array();
// Sort array
items_sort.sort(function(a,b) { return a - b;});
// Get order
for (i = 0; i < items.length; i++) {
order[i] = items.indexOf(items_sort[i]);
}

Categories

Resources