I'm learning ES6 from a tutorial and while playing with the code, I found something that I didn't understand. The code below outputs '3'.
var primaryColors = [
{ color: 'red' },
{ color: 'yellow' },
{ color: 'blue' },
];
var newColors = [];
primaryColors.reduce(function(color, primaryColor){
return newColors.push(primaryColor.color);
}, []);
Why is the return statement returning the no of data in the "stack"?
Why is reduce function outputting no of items in an array?
As Nenad Vracar said, because push returns the number of items in the array, and reduce returns the last value the callback returned.
reduce is not the right tool for this job. map is:
var newColors = primaryColors.map(function(primaryColor) {
return primaryColor.color;
});
var primaryColors = [
{ color: 'red' },
{ color: 'yellow' },
{ color: 'blue' },
];
var newColors = primaryColors.map(function(primaryColor) {
return primaryColor.color;
});
console.log(newColors);
or with an ES2015 arrow function:
var newColors = primaryColors.map(primaryColor => primaryColor.color);
var primaryColors = [
{ color: 'red' },
{ color: 'yellow' },
{ color: 'blue' },
];
var newColors = primaryColors.map(primaryColor => primaryColor.color);
console.log(newColors);
and if we're doing ES2015, we can throw in destructuring:
var newColors = primaryColors.map(({color}) => color);
var primaryColors = [
{ color: 'red' },
{ color: 'yellow' },
{ color: 'blue' },
];
var newColors = primaryColors.map(({color}) => color);
console.log(newColors);
Related
This question already has answers here:
Remove array element based on object property
(12 answers)
javascript - remove array element on condition
(11 answers)
Closed 1 year ago.
array, foods = [{ name: 'Apple', color: 'red' }, { name: 'Egg', color: 'white' }];
and here's what I tried,
let foods = [{ name: 'Apple', color: 'red' }, { name: 'Egg', color: 'white' }];
function removeRed(food) {
food.filter(function (x) {
if (x.color !== 'red') {
return true;
} else {
return false;
}
});
return foods;
When I call the function like " removeRed(foods) " the output is giving both of the property-value pairs in my array.
I'm a beginner student and this is my first Question here. Hope that someone answers :'D
}
Put return inside the function before the filter called
function removeRed(food) {
return food.filter(function (x) {
if (x.color !== 'red') {
return true;
} else {
return false;
}
});
}
Call the function to execute the code
let foods = [{ name: 'Apple', color: 'red' }, { name: 'Egg', color: 'white' }];
removeRed(foods); // [{name: 'Egg', color: 'white'}]
Best practice Make always the function more generic like this:
function remove(food, color) {
return food.filter(function (x) {
if (x.color !== color) {
return true;
} else {
return false;
}
});
}
let foods = [{ name: 'Apple', color: 'red' }, { name: 'Egg', color: 'white' }];
remove(foods,'white'); // [{name: 'Apple', color: 'red'}]
One line with ES6+ syntax:
const remove = (food, color) => food.filter(x=> x.color !== color);
you need to return the output of the filter. you were returning the original array
function removeRed(food) {
return food.filter(function (x) {
if (x.color !== 'red') {
return true;
} else {
return false;
}
});
Use this code to filter non-red items
let foods = [{ name: 'Apple', color: 'red' }, { name: 'Egg', color: 'white' }];
const filtered = foods.filter(item => item.color !== 'red');
console.log(filtered)
I need a create an one excel file with 3 worksheets. For now I wrote a function which create worksheet and workbook. I have problem because I need write data into workshet in some executed async function. Maybe some code will describe what I have to do.
var Excel = require('exceljs');
const workbook = new Excel.Workbook({
useStyles: true
})
const headers = [
{ header: 'Plik', key: 'path', width: 40 },
{ header: 'Zwierze', key: 'name', width: 12 },
{ header: 'Prawdopodobienstwo(%)', key: 'confidence', width: 24 },
{ header: 'Czas odpowiedzi(s)', key: 'responseTime', width: 20 }
];
workbook.xlsx.writeFile("./excel/Wyniki.xlsx");
setWorkSheet = (name, responses, filename) => {
workbook.xlsx.readFile(filename)
.then(function () {
const worksheet = workbook.addWorksheet(name);
worksheet.columns = headers;
for (let i = 0; i < responses.length; i++) {
worksheet.addRow(responses[i]);
}
worksheet.getRow(1).style.font = { size: 12, name: 'Bahnschrift SemiBold SemiConden' }
worksheet.getRow(1).eachCell((cell) => {
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: '993399' }
},
cell.style.font = {
color: {
argb: 'ffffff'
},
size: 14,
}
})
worksheet.eachRow((Row, rowNumber) => {
Row.alignment = {
horizontal: 'center',
}
Row.eachCell((Cell, cellNumber) => {
Cell.alignment = {
vertical: 'middle',
horizontal: 'center'
},
Cell.border = {
top: { style: 'double', color: { argb: 'black' } },
left: { style: 'double', color: { argb: 'black' } },
bottom: { style: 'double', color: { argb: 'black' } },
right: { style: 'double', color: { argb: 'black' } }
}
})
})
worksheet.views = [
{ state: 'frozen', xSplit: 1, ySplit: 1, activeCell: 'B2' },
];
return workbook.xlsx.writeFile(`${filename}`)
})
.then(function () {
console.log("Done");
})
.catch(function (err) {
console.log(err)
});
}
And this function for now create a new file with special defined name worksheet. I need execute this function 3 times and after this operations I need to have one file and 3 worksheets. Here are places where I executed this function:
async function Cognitive() {
let tab = [];
for (let i = 0; i < arrayOfFiles.length; i++) {
let x = await cognitive.cognitiveDetectLabels(arrayOfFiles[i]);
tab.push(x)
}
setWorkSheet('Cognitive', tab, "./excel/Wyniki.xlsx");
}
exports.Cognitive = Cognitive;
async function Rekognition() {
let tab = [];
const path = "./csv/Rekognition.csv";
for (let i = 0; i < arrayOfFiles.length; i++) {
let x = await rekognitionFile.callaws(arrayOfFiles[i]);
tab.push(x)
}
setWorkSheet("Rekognition", tab, "./excel/Wyniki.xlsx");
}
exports.Rekognition = Rekognition;
async function Vision() {
let tab = [];
for (let i = 0; i < arrayOfFiles.length; i++) {
let x = await vision.callVision(arrayOfFiles[i]);
tab.push(x)
}
setWorkSheet("Vision", tab, "./excel/Wyniki.xlsx");
}
exports.Vision = Vision;
When I execute one of this async function. File with worksheet always is overwritten.
However, I need to add sheets to one file (3 sheets). Anyone have some ideas about this problem ? Thank you
I have a scenario, were need to compare treeObject1 and treeObject2 to determine the exact difference at property level and find the parent of modified node.
In below provided objects, I need to get output as color blue. Since the difference is at otherObj2.
treeObject1 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "blue",
otherValue: 20,
}
}
}
treeObject2 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "Green",
otherValue: 20,
}
}
}
If you want the key "otherObj" as well let me know, that can easily be added. Otherwise here is a working version of what you were looking for.
This uses a combination of Object.keys and every
treeObject1 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "blue",
otherValue: 20,
}
}
}
treeObject2 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "Green",
otherValue: 20,
}
}
}
const findParentNode = (obj1, obj2, parent = null) => {
if(parent === null) parent = obj2;
//since the structures are the same we only get keys from the first object
const keys = Object.keys(obj1);
let result = null;
//iterate through every key
keys.every(key=>{
//if it's an object... then we recall findParentNode (recursive)
if(obj1[key] instanceof Object){
result = findParentNode(obj1[key], obj2[key], obj2);
//If result from findParentNode is not null then a difference was found.
//Return false to stop the every method.
if(result !== null) return false;
}else if(obj1[key] !== obj2[key]){
//If the objects are different we found a difference
//Set the parent as the difference
result = parent;
return false;
}
//return true to keep on looping
return true;
});
//return the result
return result;
}
console.log(findParentNode(treeObject1, treeObject2));
** note that the above snippet will return "null" if nothing was found. **
You could use a nested approach for objects and by checking the values.
function getDiffParents(object1, object2, parent = {}) {
return Object.assign(...Object.entries(object1).map(([k, v]) => v && typeof v === 'object'
? getDiffParents(v, object2[k], object1)
: v === object2[k]
? {}
: parent
));
}
var treeObject1 = { color: "red", value: 10, otherObj: { color: "blue", otherObj2: { otherColor: "blue", otherValue: 20 } } },
treeObject2 = { color: "red", value: 10, otherObj: { color: "blue", otherObj2: { otherColor: "Green", otherValue: 20 } } };
console.log(getDiffParents(treeObject1, treeObject2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have nested array's and need to delete the object based on condition.
Array:
grouplist: [
{
name: "one",
optionlist: [
{
optionitem: "green"
},
{
optionitem: "red"
}
]
},
{
name: "two",
optionlist: [
{
optionitem: "yellow"
},
{
optionitem: "red"
},
{
optionitem: "blue"
}
]
},
{
name: "three",
optionlist: [
{
optionitem: "green"
}
]
},
{
name: "four",
optionlist: [
{
optionitem: "blue"
},
{
optionitem: "red"
}
]
}
];
If the optionItem color is green, then I need to remove it completely from my array object.
This is what I have tried.
var returnedData = _.filter(grouplist, function(n) {
return _.some(n.optionlist, function(option){
return option.optionitem!= "green";
});
});
var returnedData = _.filter(grouplist, function(n){
var containsGreen = _.some(n.optionlist, function(option){
return option.optionitem === "green";
})
return !containsGreen;
});
var returnedData = _.reject(grouplist, function(n){
return _.some(n.optionlist, function(option){
return option.optionitem === "green";
});
});
The problem with filter or _.filter is that you're creating a new array. If you want to simply remove an object from the existing array without creating a new one, here's a simple vanilla JS way of doing that in the same number of lines of code:
for (var i = 0, l = grouplist.length; i < l; i++) {
var foundGreen = grouplist[i].optionlist.some(function (el) {
return el.optionitem === 'green';
});
if (foundGreen) grouplist.splice(i, 1); i--; l--;
}
DEMO
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/