Get observableArray of unique values from another obseravableArray - arrays

I'm having data like:
{ mealName: "sandwich", price: 0 },
{ mealName: "lobster", price: 34.95 },
{ mealName: "whole zebra", price: 290 },
{ mealName: "whole zebra", price: 290 },
{ mealName: "sandwich", price: 290 },
{ mealName: "whole zebra", price: 290 }
And I want to get observableArray like:
{ mealName: "sandwich"},
{ mealName: "whole zebra"},
{ mealName: "lobster"}
I've tried to reproduce it in jsFiddle, but something is wrong

unique doesn't have to be an observable array as the availableMeals is not an observable array, but since you asked I used a computed.
First I sort the array using a custom sort function. I used concat to create a copy as I didn't want to modify the order of the original array. I then loop through the sorted array and remove any duplicates:
self.unique = ko.computed(function() {
var sortedItems = self.availableMeals.concat().sort(function(left, right) { return left.mealName == right.mealName ? 0 : (left.mealName < right.mealName ? -1 : 1) });
var meal;
for (var i = 0; i < sortedItems.length; i++) {
if (!meal || meal != sortedItems[i].mealName) {
meal = sortedItems[i].mealName;
}
else {
sortedItems.splice(i, 1);
i--;
}
}
return sortedItems;
});
jsfiddle

var uniqueMeals = ko.computed(function () {
var uniqueMealNames = mealData().reduce(function(uniqueMeals, meal) {
if(uniqueMeals.indexOf(meal.mealName) === -1) {
uniqueMeals.push(meal.mealName);
}
return uniqueMeals;
}, []);
return uniqueMealNames.map(function(mealName) {
return {mealName: mealName};
});
});
Some suggestions: it's probably be better to store the unique values in an array of strings, not objects, i.e. ["sandwich", "whole zebra", "lobster"]. If so, you can drop the last line from my above code.
Also, you might consider looking into the lodash library. With lodash, this would be:
var uniqueMeals = ko.computed(function () {
return _.unique(_.pluck(mealData, "mealName"));
})

Related

How to find out number of elements in MongoDB array?

My collection of products consists of _id, product/title, product/price and reviews. Reviews is an array with all reviews for that specific product. I am trying to print out 10 products with the largest number of reviews but can't find the right solution.
This is what I tried so far:
var mapFunction = function() {
emit(this._id, {
product: this,
count_reviews: this.reviews.length
});
};
var reduceFunction = function(key, values) {
var count = 0;
var product;
values.forEach(function(value) {
count += value.count_reviews;
product = value.product
});
return { count_reviews: count, product: product};
};
db.products.mapReduce(mapFunction, reduceFunction, {
out: { inline: 1},
query: {},
sort: { count_reviews: -1 },
limit: 10
});
When I run this code it prints out 10 elements, but not with the largest number of reviews.
I wouldn't use mapReduce (unless you're on a version so old you have to)
I'd use an aggregation, if you have strict data - you can omit the $match, if you have "strictish" data (e.g., it's an array or missing) you can use a simpler match: { reviews: { $exists: true } }
db.products.aggregate([
{
$match: {
"value.reviews": { $type: "array" }
}
},
{
$set: { review_count: { $size: "$value.reviews" } }
},
{
$sort: { review_count: -1 },
},
{
$limit: 10
}
])

Trying to filter an array and return a new array with the met criteria

Im trying to make a function that returns an Array (javascript). The original array contains objects (pizzas) and I have to return a new array WITHOUT the pizzas that contain pineapple on it. I dont seem to understand why it doesnt work.
I have tried to declare a new array and push() the [i] values that meet the criteria (!== 'pineapple'). But im clearly missing something.
I just started learning JS this week so tools like filter and map aren't possible for me yet.
thanks in advance!
const pizzas = [
{ type: 'margherita', size: '5' },
{ type: 'funghi', size: '6' },
{ type: 'hawaii', size: '7' },
{ type: 'vegetarian', size: '8' },
{ type: 'pineapple', size: '9' },
];
function filterPizzas(pizzas) {
const noPineapple = [];
for (let i = 0; i < pizzas.length; i++) {
if (pizzas[i].type !== 'pineapple') {
noPineapple.push(pizzas[i]);
}
}
return noPineapple;
}
Your code looks almost correct, although there is no use for storing the catalogue inside your FilterPizzas function and then also take in pizzas as a function argument. I assume you want to pass this list of pizzas (your catalogue) to your function and then return the filtered result.
const pizzas = [
{ type: 'margherita', price: '5' },
{ type: 'funghi', price: '6' },
{ type: 'hawaii', price: '7' },
{ type: 'vegetarian', price: '8' },
{ type: 'pineapple', price: '9' },
]
function filterPizzas(pizzas) {
const filteredPizzas = [];
for (let i = 0; i < pizzas.length; i++) {
if (pizzas[i].type !== 'pineapple') {
filteredPizzas.push(pizzas[i]);
}
}
return filteredPizzas
}
Have a look in the console of this working codesandbox example.
Option 1:
function filterPizzas(pizzas) {
const filteredPizzas = [];
for (let i = 0; i < pizzas.length; i++) {
const pizza = pizzas[i];
const pizzaType = pizza.type;
const isNotPineapple = pizzaType !== "pineapple";
if (isNotPineapple) {
filteredPizzas.push(pizza);
}
}
return filteredPizzas;
}
Option 2:
function filterPizzas(pizzas) {
let array = pizzas.filter(pizza => {
return pizza.type != 'pineapple';
});
return array;
}

sort an array of objects on multiple key using array-sort

I have a requirement where the array of objects needs to be sorted on certain keys. The keys with which it needs to be sorted is dynamic and it is Not fixed.
I came across array-sort in npm library. Using that, am able to sort on multiple keys but it sorts only on ascending order.
const input = [{id:'1',name:'John',city:'Denver',State:'CO'},
{id:'2',name:'Smith',city:'San Fransisco',State:'CA'},
{id:'3',name:'Adam',city:'Concord',State:'CA'},
{id:'1',name:'John',city:'Concord',State:'CA'}]
I want to sort on State (asc), city (asc) and id (desc). My output should look like
[
{id:'3',name:'Adam',city:'Concord',State:'CA'},
{id:'1',name:'John',city:'Concord',State:'CA'},
{id:'2',name:'Smith',city:'San Fransisco',State:'CA'},
{id:'1',name:'John',city:'Denver',State:'CO'}]
Can anyone please let me know how i can implement sorting on descending using array-sort
Thanks
Maybe you want a JavaScript function like this?
function multicolumnSort(data, orders) {
return data.sort((e1, e2) => {
for (var i = 0; i < orders.length; i++)
if (e1[orders[i].column] != e2[orders[i].column])
return orders[i].desc ^ e2[orders[i].column] < e1[orders[i].column]? 1 : -1;
return 0;
});
}
Then, you may call the function with your order keys:
let orders = [
{
column: 'State'
},
{
column: 'city'
},
{
column: 'id',
desc: true
}
];
let result = multicolumnSort(input, orders);
Check my code
function DESC(i, ii) { // DESC
return (i[key] > ii[key]) ? -1 : ((i[key] < ii[key]) ? 1 : 0);
}
function ASC(i, ii) { // ASC
return (i[key] > ii[key]) ? 1 : ((i[key] < ii[key]) ? -1 : 0);
}
function StartSort(data, myArray, order) {
// data - row for sorting, array - array fo sorting, order - order of sorting
key = data;
arr = myArray;
if (order.toUpperCase() == "ASC") {
sortedArray = arr.sort(ASC);
} else {
sortedArray = arr.sort(DESC);
}
return sortedArray;
}
//sorting started
const input = [{
id: '1',
name: 'John',
city: 'Denver',
State: 'CO'
},
{
id: '2',
name: 'Smith',
city: 'San Fransisco',
State: 'CA'
},
{
id: '3',
name: 'Adam',
city: 'Concord',
State: 'CA'
},
{
id: '1',
name: 'John',
city: 'Concord',
State: 'CA'
}
]
let output1 = StartSort('state', input, 'ASC');
output1 = StartSort('city', output1, 'ASC');
output1 = StartSort('id', output1, 'DESC');
console.log(output1);

ES6 : Create objects in a given format from array of key values

var result = {445: "L005.0", 455: "L006.0", 456: "L007.0", 457: "L008.0", 458: "L009.0", 459: "L027.0", 467: "L005.7", 580: "L001.0", 581: "L002.0", 587: "L003.0"};
From this "result", I want to output an object like this
{
"445": {
name: result[445],
icon: "fa-search"
},
"455": {
name: result[455],
icon: "fa-search"
},
"456": { ... },
"457": { ... },
...
...
}
So you need to iterate over keys to construct new object o;
let res={}; //initializing
for(let i of Object.keys(result))
{
res[i]={
"name": result[i],
"icon":"fa-seach"
}
}
console.log(res) //to test

Group by on a complex object in AngularJS

I've an array that contains assignments of employees on tasks, it looks like something like this:
$scope.assignments = [
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Kill everyone", project:"Destruction"
},
date: {
day:"01/01", year:"1985"
}
},
{
employee: {
id:"2", firstname:"Luke", lastname:"Skywalker"
},
task: {
name:"Find daddy", project:"Star Wars"
},
date: {
day:"65/45", year:"1000000"
}
},
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Save the world", project:"Destruction"
},
date: {
day:"02/01", year:"1985"
}
}
];
I would like to group by employee, for having something like this:
$scope.assignmentsByEmployee = [
{ //First item
id:"1",
firstname:"John",
lastname:"Rambo",
missions: [
{
name:"Kill everyone",
date:"01/01",
year:"1985"
},
{
name:"Save the world",
date:"02/01",
year:"1985"
}
]
},
{ //Second item
id="2",
firstname:"Luke",
lastname:"Skywalker",
missions: [
name:"Find daddy",
date:"65/45",
year:"1000000"
]
}
];
Is their a simple way to do this ? I tried something with a double forEach, but it leads me nowhere.
Hope I'm understandable :)
Thanks !
You should just be able to loop through the assignments array and create a 'keyed array' (which just means using an object in JavaScript) on employee ID. Then you just fill up the missions array as required.
Something like
// initialise a holding object
var assignmentsByEmployee = {};
// loop through all assignemnts
for(var i = 0; i < $scope.assignments.length; i++) {
// grab current assignment
var currentAssignment = $scope.assignments[i];
// grab current id
var currentId = currentAssignment.employee.id;
// check if we have seen this employee before
if(assignmentsByEmployee[currentId] === undefined) {
// we haven't, so add a new object to the array
assignmentsByEmployee[currentId] = {
id: currentId,
firstname: currentAssignment.employee.firstname,
lastname: currentAssignment.employee.lastname,
missions: []
};
}
// we know the employee exists at this point, so simply add the mission details
assignmentsByEmployee[currentId].missions.push({
name: currentAssignment.task.name,
date: currentAssignment.date.day,
year: currentAssignment.date.year
});
}
These leaves assignmentsByEmployee as an object, but you can simply foreach through it and convert it back to an array if required. E.g:
$scope.assignmentsByEmployee = [];
for(var employeeId in assignmentsByEmployee) {
$scope.assignmentsByEmployee.push(assignmentsByEmployee[employeeId]);
}

Resources