import get from "lodash.get";
const x = [
{
value: 1
},
{
value: {
min: undefined,
max: 2
}
}
];
console.log(
"valid: ",
x.every(o => o.value || (get(o, "value.min") && get(o, "value.max")))
);
https://codesandbox.io/s/modest-dijkstra-g42yy
I expect the valid to be false but it returned true although the value.min is undefined. What is the problem here?
The problem is that your first condition (o.value) returns true for the second item--since value is an object and therefore not falsy--so your check for min/max never runs.
const x = [
{
value: 1
},
{
value: {
min: undefined,
max: 2
}
}
];
// utility to check for null/undefined
const c = v => v != null;
console.log(x.every(({ value }) => (
typeof value === 'object'
? c(value.min) && c(value.max)
: c(value)
)));
const opb = {
'e' : 1,
'3' : 2,
'4' : {'ee':12}
}
Object.entries(opb).forEach(el => {console.log(el[1] !== typeof 'object' , typeof el[1])})
Hello im building a check that checks if the first value of an object property is another object.
I am doing this as follow:
const opb = {
'e' : 1,
'3' : 2,
'4' : {'ee':12}
}
Object.entries(opb).forEach(el => {console.log(el[1] !== typeof 'object' , el[1])})
Somehow everything returns true, eventho one should be an object (false).
It should be typeof el[1] !== 'object'.
const opb = {
'e' : 1,
'3' : 2,
'4' : {'ee':12}
}
Object.entries(opb).forEach(el => {console.log(typeof el[1] !== 'object' , el[1])})
I have this object:
let arr = [{
id : 1,
usr : 'pimba',
xyz: null
},
{
id : 2,
usr : 'aloha',
xyz: {
xyz_id: 2
}
},
{
id : 3,
age : 'pruu',
xyz: null
}];
As you can notice, sometimes xyz is null and sometimes it's not.
I need to recognize whether it is null or not, so I can read it.
I was trying to use map() function but I can't set some sort of filter to only execute the annonymous function when it is NOT null.
I managed to do something like this:
let result = Object.values(arr).map(function(row){
if(row['xyz'] != null) {
console.log(row['xyz_id']);
}
});
what If I want a new array containing ONLY xyz_id ? Is there a shorter version ?
Second case:
There are more than 1 value inside xyz and it's NOT "named".
let arr = [{
id : 1,
usr : 'pimba',
xyz: null
},
{
id : 2,
usr : 'aloha',
xyz: {
xyz_id: {"value1Here", "Value2Here"}
}
},
{
id : 3,
age : 'pruu',
xyz: null
}];
It seems you want to map the array only for the elements that have not-null xyz property. One option is using both .filter and .map methods. Another option is using the .reduce method:
let result = arr.reduce(function(ret, row) {
// assuming `xyz` can be only `null` or an object
if ( row.xyz !== null ) {
ret.push(row.xyz.xyz_id);
}
return ret;
}, []);
You might want to look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const notNull = arr.filter(elm => elm.xyz !== null);
var a = {one: 1, two: null, three: 3, four: true}
var y = []
let scan = (obj) => {
Object.keys(obj).forEach(x => {
if (obj[x] === null) {
console.log('Its null')
} else {
// Extend here to datatypes
y.push(obj[x])
}
});
}
scan(a)
console.log(y)
I need help putting together an array search that is based on multiple conditions. Furthermore, all the conditions are conditional, meaning I may or may not need to filter on those conditions. What I have:
Array of objects to filter:
var data = [{
"_id" : ObjectId("583f6e6d14c8042dd7c979e6"),
"transid" : 1,
"acct" : "acct1",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 2,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 3,
"acct" : "acct2",
"transdate" : ISODate("2016-07-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 4,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 5,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c152g2"),
"transid" : 6,
"acct" : "acct3",
"transdate" : ISODate("2016-10-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
}]
I am filtering the above array of objects based on another array of mixed elements. The elements represent the following search fields:
"searchstring": to search on all fields in the data array for any
matched text sequence
object with key values reprsenting account type and a true or false
for value indicating if it should be used to filter
startdate to filter transdate on
enddate to filter transdate
category name to filter category on
The array that has the search conditions looks like this (but if some of the fields are not necessary they will be set to undefined or just an empty string or array):
var filtercondition = {
"p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
}
What is the best way to accomplish this? What I've devised is a separate search for each element in the filter array, but this seems non optimal and very tedious. I'm open to a redesign of my setup...
// You wrote that it's an array, so changed the braces
var filtercondition = ["p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
];
var filtered = data.filter(o => {
if(filtercondition[0] && !o.category.includes(filtercondition[o])) { // checking just the category, but you can check if any of more fields contains the conditions
return false;
}
if(filtercondition[1]) {
for(var key in filtercondition[1]) {
if(filtercondition[1][key] === true && o.acct != key) {
return false;
}
}
}
if(filtercondition[2] && o.transdate < filtercondition[2]) {
return false;
}
if(filtercondition[3] && o.transdate > filtercondition[3]) {
return false;
}
if(filtercondition[4] && o.category !== filtercondition[4]) {
return false;
}
return true;
});
Two notes:
- changed the braces of filtercondition so that it is an array, however I would suggest to use an object instead.
- this {acct1:true,acct2:false,acct3:true...} sample doesn't make sense for me, since it suggests that the acct field should be acct1 and acct3 at the same time.
Create an array of functions, each function representing a condition.
Here's some sample code which demonstrates the approach...
var conditions = [];
// Dynamically build the list of conditions
if(startDateFilter) {
conditions.push(function(item) {
return item.transdate >= startDateFilter.startDate;
});
};
if(categoryFilter) {
conditions.push(function(item) {
return item.cateogry === categoryFilter.category;
});
};
// etc etc
Once you have an array of conditions, you can use Array.prototype.every to run each condition on an item.
var itemsMatchingCondition = data.filter(function(d) {
return conditions.every(function(c) {
return c(d);
});
});
Or, using the more compact arrow functions:
const itemsMatchingCondition = data.filter(d => conditions.every(c => c(d));
First, you'll want to use brackets for your array not curly braces:
var filtercondition = [
"p",
{acct1:true,acct2:false,acct3:true...},
"2016-06-01",
"2016-11-30",
"category3"
];
Then again, I don't think that an array is the best data type for that. Try an object like this:
var filtercondition = {
query: "p",
accounts: {acct1:true,acct2:false,acct3:true...},
date1: "2016-06-01",
date2: "2016-11-30",
category: "category3"
};
Then, try using Array.prototype.filter:
var filtered = data.filter(function(obj) {
for (var key in filtercondition) {
// if condition not met return false
}
return true;
});
I'd go with a bunch of small granular functions and compose them.
//only some utilities, from the top of my mind
var identity = v => v;
//string-related
var string = v => v == null? "": String(v);
var startsWith = needle => haystack => string(haystack).startsWith(needle);
var endsWith = needle => haystack => string(haystack).endsWith(needle);
var contains = needle => haystack => string(haystack).contains(needle);
//do sth with an object
var prop = key => obj => obj != null && prop in obj? obj[prop]: undefined;
var someProp = fn => obj => obj != null && Object.keys(obj).some(k => fn(k) );
var someValue = fn => obj => obj != null && Object.keys(obj).some(k => fn(obj[k]) );
//logic
var eq = b => a => a === b;
var not = fn => function(){ return !fn.apply(this, arguments) };
var and = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) && b.apply(this, arguments);
});
var or = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) || b.apply(this, arguments);
});
//composition
var compose = (...funcs) => funcs.reduce((a, b) => v => return a(b(v)));
var chain = (...funcs) => funcs.reduceRight((a, b) => v => return a(b(v)));
//and whatever else you want/need
//but stay granular, don't put too much logic into a single function
and an example composition:
var filterFn = and(
//some value contains "p"
someValue(contains("p")),
//and
chain(
//property "foo"
prop("foo"),
or(
//either contains "asdf"
contains("asdf"),
//or startsWith "123"
startsWith("123")
)
),
)
since I don't know how you build your filterconditions, I cannot tell you exactly how to parse them into such a composition, but you could compose them like this:
//start with something basic, so we don't ever have to check wether filterFn is null
var filterFn = identity;
//and extend/compose it depending on some conditions
if(/*hasQuery*/){
filterFn = and(
// previous filterFn(obj) && some value on obj contains `query`
filterFn,
someValue(contains(query)))
)
}
if(/*condition*/){
//extend filterFn
filterFn = or(
// (obj.foo === null) || previous filterFn(obj)
chain(prop("foo"), eq(null)),
filterFn
);
}
and so on
First, some points:
Your data object is invalid if you're going to use it in the browser. Probably the data comes from MongoDB, right? Your backend (data source) should have a method to encode it properly and remove ObjectID and ISODate references.
Your filtercondition is not a valid JavaScript object/JSON. Check my example.
So, you can filter your data array with Array#filter method.
Something like that:
let data = [{
"_id" : "583f6e6d14c8042dd7c979e6",
"transid" : 1,
"acct" : "acct1",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category1",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 2,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category2",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 5,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category3",
"amount" : 103
}];
let filterToApply = {
acct: {
acct1: true,
acct2: false,
acct3: true
},
initialDate: "2016-06-01",
finalDate: "2016-11-30",
category: "category3"
}
let filterData = (array, filter) => {
return array.filter( (item) => {
/* here, you iterate each item and compare with your filter,
if the item pass, you must return true. Otherwise, false */
/* e.g.: category check (if present only) */
if (filter.category && filter.category !== item.category)
return false;
}
/* add other criterias check... */
return true;
});
}
let dataFiltered = filterData(data, filterToApply);
console.log(dataFiltered);
If you want to filter an array with multiple conditions and the conditions may be optional, then use the following method.
const data = [
{ name: 'John', age: 25, city: 'New York' },
{ name: 'John', age: 25, city: 'New' },
{ name: 'Jane', age: 32, city: 'Los Angeles' },
{ name: 'Bob', age: 45, city: 'New York' },
{ name: 'Alice', age: 38, city: 'Los Angeles' }
];
const filteredData = (n, c, a) => data.filter(item => {
if (n || c || a) {
return (n ? item.name === n : true) && (c ? item.city === c : true) && (a ? item.age === a : true); // keep adding conditons as much as u want
}
});
console.log(filteredData('John', null, 25));
console.log(filteredData(null, 'Los Angeles', 38));
console.log(filteredData(null, 'Los Angeles', null));
You can chain as many as conditions
This question is for purely for learning purposes. funfunfunction on youtube says that
Any list higher order list transformation can be written in Array.reduce()
Audio/video Reference: https://youtu.be/Wl98eZpkp-c?t=138.
Question:
Purely for learning how would one rewrite Array.every() with Array.reduce()
This question stems from my previous question here
Javascript Example:
var approved1 = [
{
dateApproved: new Date(),
id: 1,
},
{
dateApproved: new Date(),
id: 2,
}
];
var approved2 = [
{
dateApproved: null,
id: 1,
},
{
dateApproved: new Date(),
id: 2,
}
];
approved1.every(a => a.dateApproved != null) ? 'APPROVED' : 'PENDING'
// 'APPROVED'
approved2.reduce(every) ? 'APPROVED' : 'PENDING'
// 'PENDING'
I struggle with where I store the currently passed values. Where do I store the "passed" values like Array.every() does?
function every(previousValue, currentValue, currentIdx, arr) {
if(previousValue.dateApproved !== null && currentValue.dateApproved !== null) {
return currentValue;
}
}
You can use reduce instead of every and make it work, but I'd suggest you to use them in there apt places. Both have distinctive requirement.
array.reduce
array.reduce(callback(curentElement, nextElement, index, array),[initialCurrentElement])
Array.reduce has 4 args.
currentElement: By default, this will be 1st element in array for 1st iteration and then, this variable will hold value that you return. If an initial value is passed, then it will hold that and start from there.
nextElement: By default it holds second or next element. If initial value is passed, this will hold first value.
index: this holds the index of current element.
array: This is the parent array on which we are looping.
initialCurrentElement: This is an optional argument. If this is passed, looping starts with this.
Following is a sample showing an illustration:
Note:
Array.every will break on first falsey condition. Array.reduce will not.
Array.reduce is meant to compare 2 values of same array where as Array.every is meant to compare each values to an expression. Using .reduce instead of .every is just an overkill.
var approved2 = [{
dateApproved: null,
id: 1,
}, {
dateApproved: new Date(),
id: 2,
}];
var everyResult = approved2.every(x => {
console.log(x.dateApproved)
x.dateApproved !== null
})
console.log(everyResult)
var reduceResult = approved2.reduce((p, c) => {
console.log(c.dateApproved)
return !p ? p : c.dateApproved !== null
}, true)
console.log(reduceResult? 'Approved': 'Rejected')
This should do the trick:
function every(pre, curr) {
return pre.dateApproved != null && curr.dateApproved != null
}
approved1.reduce(every) ? 'APPROVED' : 'PENDING' // APPROVED
approved2.reduce(every) ? 'APPROVED' : 'PENDING' // PENDING
And I'm pretty sure you can do it without curr, just pre.
var status = approved1.reduce( val => (val.dateApproved) ? 'APPROVED': 'REJECTED')
var approved1 = [
{
dateApproved: new Date(),
id: 1,
},
{
dateApproved: new Date(),
id: 2,
}
];
var approved2 = [
{
dateApproved: new Date(),
id: 1,
},
{
dateApproved: null,
id: 2,
},
{
dateApproved: new Date(),
id: 2,
}
];
console.log(approved2.reduce( (prev, curr) => (prev.dateApproved && curr.dateApproved) ? true : false) ? 'APPROVED':'REJECTED')
console.log(approved1.reduce( (prev, curr) => (prev.dateApproved && curr.dateApproved) ? true : false) ? 'APPROVED':'REJECTED')
You might roughly implement it as folows
Array.prototype.every = function(cb){
return this.reduce((p,c,i,a) => i === 1 ? cb(p,i-1,a) && cb(c,i,a)
: p && cb(c,i,a));
};
var arr = [9,2,3,9,12,5],
brr = [1,2,3,4,5,6,9];
console.log(arr.every(e => e < 10));
console.log(brr.every(e => e < 10));