Trying to see if data in one array matches the data in another. I have an array of objects, like so -
var ProductsList =
[
{"Name": "Product A"; "Rating": "3"},
{"Name": "Product B"; "Rating": "2"},
{"Name": "Product C"; "Rating": "1"},
];
I then want to compare this product list with user selected values, which come in an array that I get based on the values they selected via checkboxes. So if they selected 1, 2, 3 - all products should be shown, if they selected 1 - then only product A is shown.
I tried to use $.grep to do the filtering but I'm running into an issue filtering via array values. Let's hard code the user filer to all values as an example.
userFilterArray.Rating = [1, 2, 3];
function filter(ProductsList, userFilterArray)
filteredList = $.grep(ProductList, function(n) {
return (n.Rating == userFilterArray.Rating);
});
Obviously this doesn't work as I'm comparing n.Rating which is a string to an array but I'm not sure how to compare the string to string in this case.
Would grep be the easiest way to do this? Should I use a combo of .each .each? Maybe neither?
After a bunch of syntax and other fixes, I think this is what you're after:
var ProductsList = [
{"Name": "Product A", "Rating": 3},
{"Name": "Product B", "Rating": 2},
{"Name": "Product C", "Rating": 1}
];
var userFilterArray = [1, 3];
function filter(list, filterArr) {
return $.grep(list, function(obj) {
return $.inArray(obj.Rating, filterArr) !== -1;
});
}
var filteredList = filter(ProductsList, userFilterArray)
console.log( filteredList );
DEMO: http://jsfiddle.net/vK6N9/
Related
Still learning here. This one as simple as it seems, has beaten me up. I have managed to get the answer. But, when I do, I am getting more than one name coming out of my if statement. I used a new set to remove the duplicate names in the names array. But frankly, that seems lazy to me and I feel something can be done that is better.
Can someone show me some ways I'm missing to better go through this problem? I tried flattening and that didn't work either. Thank you for your help!
Here are the directions given to me:
Create a function passingStudents that accepts an array of student objects.
It should iterate through the list of students and return an array of the names of all the students who have an average grade of at least 70.
function passingStudents(students) {
const names = [];
students.forEach(student => {
student.grades.forEach(grade => {
if(grade.score >= 70) {
names.push(student.name);
}
});
});
let uniqueChars = [...new Set(names)];
return uniqueChars;
}
//Uncomment the lines below to test your function:
var students = [
{
"name": "Marco",
"id": 12345,
"grades": [{"id": 0, "score": 65}, {"id": 1, "score": 75}, {"id": 2, "score": 85}]
},
{
"name": "Donna",
"id": 55555,
"grades": [{"id": 0, "score": 100}, {"id": 1, "score": 100}, {"id": 2, "score": 100}]
},
{
"name": "Jukay",
"id": 94110,
"grades": [{"id": 0, "score": 65}, {"id": 1, "score": 60}, {"id": 2, "score": 65}]
}
];
console.log(passingStudents(students)); // => [ 'Marco', 'Donna' ]
The reason your solution introduces multiple people in the names array is that it adds the name for each grade they have that is at least 70. This means it will return a student if any of their grades is at least 70 rather than if their average grade is at least 70. While your solution may pass the test case provided, it will not work for every case in general. A better solution is to average the grades by using reduce and filter the original list of students based on whether their average is above 70. Then you can map the filtered students to their name.
function passingStudents(students) {
return students
.filter((student) => {
const { grades } = student;
const average = grades.reduce((sum, grade) => sum + grade.score, 0) / grades.length;
return average >= 70;
})
.map((student) => student.name);
}
I need a list of unique objects based on a specific key.
const array = [
{"name": "Joe", "age": 42},
{"name": "Donald", "age": 69},
{"name": "John", "age": 42},
]
How can i get a list of unique objects selected from the list assuming i want a list of people with unique ages.
const result = [
{"name": "Joe", "age": 42},
{"name": "Donald", "age": 69}
]
How can this be done in a performant way, is there a better way than iterating through the elements in a foreach and adding it if it does not exist in the resulting array?
One way is to feed the array to a Map where you key them by age. That will eliminate duplicates, only retaining the last in the series of duplicates. Then extract the values again from it:
const array = [{"name": "Joe", "age": 42},{"name": "Donald", "age": 69},{"name": "John", "age": 42}];
const uniques = Array.from(new Map(array.map(o => [o.age, o])).values());
console.log(uniques);
If you want to retain the first of duplicates, then first reverse the array.
Another option is to track seen values, here using a Set passed as a closure and checking for values using its .has() method to return a boolean to a filter() call. This will retain the first seen objects.
const array = [
{ "name": "Joe", "age": 42 },
{ "name": "Donald", "age": 69 },
{ "name": "John", "age": 42 },
]
const unique = (seen => array.filter(o => !seen.has(o.age) && seen.add(o.age)))(new Set());
console.log(unique)
I'm practicing how to maniupulate data in JS in this article: http://learnjsdata.com/combine_data.html
var articles = [
{"id": 1, "name": "vacuum cleaner", "weight": 9.9, "price": 89.9, "brand_id": 2},
{"id": 2, "name": "washing machine", "weight": 540, "price": 230, "brand_id": 1},
{"id": 3, "name": "hair dryer", "weight": 1.2, "price": 24.99, "brand_id": 2},
{"id": 4, "name": "super fast laptop", "weight": 400, "price": 899.9, "brand_id": 3}
];
var brands = [
{"id": 1, "name": "SuperKitchen"},
{"id": 2, "name": "HomeSweetHome"}
];
articles.forEach(function(article) {
var result = brands.filter(function(brand){
return brand.id === article.brand_id;
});
delete article.brand_id;
article.brand = (result[0] !== undefined) ? result[0].name : null;
});
I'm confused with the last part: article.brand = (result[0] !== undefined) ? result[0].name : null;
I understand the conditional operation: it wants to have null value if result[0] is not defined. But I'm wondering what result[0] refers to. I thought it would take first object: {"id":2, "name": "HomeSweetHome"} so there should be for loop to iterate all objects in order to see if objects meet the condition? Could you inform me what I'm missing or/and what result[0] refers to?
Thanks,
result[0] will be undefined in case there is no element in result. result is expected to be an array of brands filtered by the filter operation
The filtered array result will have same brand as that of the current article in the outer foreach loop. The filter condition is going to achieve that.
It looks like in this particular case you will get only one element in result array always as there are unique brand ids. It might have more elements in case of duplicated brand ids.
result[0] points to first element in the array result
Consider the following example:
var products = {
"Products": [{
"Title": "A",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 1", "Market 2", "Market 3", "Market 4"]
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 2"]
}]
}, {
"Title": "B",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 3"]
}, {
"Name": "Market",
"Properties": "Market 1"
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 3"]
}]
}, {
"Title": "C",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 2", "Market 3"]
}, {
"Name": "Technology",
"Properties": ["Tech 2", "Tech 3"]
}]
}]
}
I'm trying to filter products by their properties so consider I'm using an array to keep track of my selected filters:
var filters = ['Type 3', 'Tech 1'];
With these filters I would like to return product A and product B.
I currently have this:
var flattenedArray = _.chain(products).map('Categories').flatten().value();
var result= _.some(flattenedArray , ['Properties', 'Tech 1']);
But I'm stuck on how to combine the properties for a combined search.
Use _.filter() to iterate the products. For each product combine the list of properties using _.flatMap(), and use _.intersection() and _.size() to find the amount of filters that exist in the categories. Compare that to the original number of filters, and return comparison's response.
var products = {"Products":[{"Title":"A","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 1","Market 2","Market 3","Market 4"]},{"Name":"Technology","Properties":["Tech 1","Tech 2"]}]},{"Title":"B","Categories":[{"Name":"Type","Properties":["Type 1","Type 3"]},{"Name":"Market","Properties":"Market 1"},{"Name":"Technology","Properties":["Tech 1","Tech 3"]}]},{"Title":"C","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 2","Market 3"]},{"Name":"Technology","Properties":["Tech 2","Tech 3"]}]}]};
var filters = ['Type 3', 'Tech 1'];
var result = _.filter(products.Products, function(product) {
return filters.length === _(product.Categories)
.flatMap('Properties')
.intersection(filters)
.size();
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
If I understand you question correctly, this code may help:
_.filter(
products.Products,
product => _.difference(
filters,
_.chain(product.Categories).map(category => category.Properties).flatten().value()
).length === 0
);
It calculates a union of all properties for each product:
_.chain(product.Categories).map(category => category.Properties).flatten().value()
And then checks that it contains all filters array elements, using _.difference method.
Hope it helps.
another fancy way through _.conforms
var res = _.filter(
products.Products,
_.conforms({'Categories': function(categories) {
return _.chain(categories)
.flatMap('Properties') // flat arrays
.uniq() // remove dublicates
.keyBy() // transform to objects with Properties keys
.at(filters) // get objects values by filters
.compact() // remove undefineds
.size() // get size
.eq(filters.length) // compare to filters size
.value();
}
}))
This will work for a list of items where the givenProperty you want to filter on is either a string like 'doorColour' or an array of strings representing the path to the givenProperty like ['town', 'street', 'doorColour'] for a value nested on an item as town.street.doorColour.
It also can filter on more than one value so you could you just need pass in an array of substrings representing the string values you want to keep and it will retain items that have a string value which contains any substring in the substrings array.
The final parameter 'includes' ensures you retain these values if you set it to false it will exclude these values and retain the ones that do not have any of the values you specified in the substrings array
import { flatMap, path } from 'lodash/fp';
const filteredListForItemsIncludingSubstringsOnAGivenProperty = (items, givenProperty, substrings, including=true) => flatMap((item) =>
substrings.find((substring) => path(givenProperty)(item) && path(givenProperty)(item).includes(substring))
? including
? [item]
: []
: including
? []
: [item])(items);
E.g. fLFIISOAGP(contacts, ['person','name'], ['Joh','Pau',Pet']);
with items of structure {contact, business:null, personal:{name:'John'}}.
For the original question - this will also work - I would use this repeatedly on a list of items to filter with different keys to filter on more than one property.
const firstFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
products.Products,
["Categories", "0", "Properties"],
["Type 3"]);
const secondFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
firstFilteredResult,
["Categories", "2", "Properties"],
["Tech 1"]);
expect(secondFilteredResult[0]['Title']).to.equal( "A");
expect(secondFilteredResult[1]['Title']).to.equal( "B");
expect(secondFilteredResult.length).to.equal(2);
I have an array of objects like the following :
var array = {
"112" : {
"id": "3",
"name": "raj"
},
"334" : {
"id": "2",
"name": "john"
},
"222" : {
"id": "5",
"name": "kelvin"
}
}
Now i want to sort the array in ascending order of id and then restore it in array. I tried using sort() but could not do it. Please help how to do so that when i display the data from the array it comes sorted.
Assuming you meant your code to be an array of objects, ie:
var unsortedArray = [
{ id: 3, name: "raj" },
{ id: 2, name: "john" },
{ id: 5, name: "kelvin" }
];
Then you would be able to sort by id by passing a function to Array.sort() that compares id's:
var sortedArray = unsortedArray.sort(function(a, b) {
return a.id - b.id
});
As others have pointed out, what you have is an object containing objects, not an array.
var array = {
"112" : {
"id": "3",
"name": "raj"
},
"334" : {
"id": "2",
"name": "john"
},
"222" : {
"id": "5",
"name": "kelvin"
}
}
var sortedObject = Array.prototype.sort.apply(array);
result:
{
"112": {
"id": "3",
"name": "raj"
},
"222": {
"id": "5",
"name": "kelvin"
},
"334": {
"id": "2",
"name": "john"
}
}
That isn't an array, it is an object (or would it if it wasn't for the syntax errors (= should be :)). It doesn't have an order.
You could use an array instead (making the current property names a value of a key on the subobjects).
Alternatively, you could use a for loop to build an array of the key names, then sort that and use it as a basis for accessing the object in order.
JavaScript objects are unordered by definition. The language specification doesn't even guarantee that, if you iterate over the properties of an object twice in succession, they'll come out in the same order the second time.
If you need things to be ordered, use an array and the Array.prototype.sort method.
That is an object but you can sort an array ilke this:
Working Demo: http://jsfiddle.net/BF8LV/2/
Hope this help,
code
function sortAscending(data_A, data_B)
{
return (data_A - data_B);
}
var array =[ 9, 10, 21, 46, 19, 11]
array.sort(sortAscending)
alert(array);
Not many people knows that Array.sort can be used on other kinds of objects, but they must have a length property:
array.length = 334;
Array.prototype.sort.call(array, function(a, b) {return a.id - b.id;});
Unfortunately, this doesn't work well if your "array" is full of "holes" like yours.