Order By custom order in object inside property - javascript

I need to sort an array of objects by a property of a sub-object:
foo = [
{
bar: {
order: "hello"
}
},
{
bar: {
order: "something"
}
},
{
bar: {
order: "else"
}
},
]
If I want the order of the foo objects to based on a custom order (not alphabetical!) set by order values like
{ "something": 1, "hello": 2, "else": 3 }
with something like _orderBy(foo, indexOfMyCustomOrder, 'desc'), how can I achieve this? Or do I need to separate this logic into two functions?

Define indexOfMyCustomOrder as follows:
const indexOfMyCustomOrder = o => order[o.bar.order];
... where the order variable should be the object that defines the sequence for each possible value of the order property.
See snippet:
const foo = [{bar:{order:"hello"}},{bar:{order: "something"}},{bar:{order:"else"}}];
const order = { "something": 1, "hello": 2, "else": 3 };
const result = _.orderBy(foo, o => order[o.bar.order]);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

You can do it like this:
const foo = [{ bar: { order: "hello" } }, { bar: { order: "something" } }, { bar: { order: "else" } } ]
let order = { something: 0, hello: 1, ["else"]: 2 }
console.log(_.orderBy(foo, x => order[x.bar.order]))
console.log(_.orderBy(foo, x => order[x.bar.order], 'desc'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Where you defined your order by index map and use that to filter the data.

You can do this without lodash using a function, where you get the keys of your custom order, you sort them based on their value and the mode (desc or asc) and then reduce that, filtering the array you want ordered adding each time the elements. Hope this helps.
const foo = [{
bar: {
order: "hello"
}
},{
bar: {
order: "something"
}
},{
bar: {
order: "else"
}
},{
bar: {
order: "else"
}
},{
bar: {
order: "anotherelse"
}
}];
const order = { "something": 1, "hello": 3, "else": 2, "missing": 4, "anotherelse": 2 };
const orderWith = (array, order, desc) =>
Object.keys(order)
.sort((a, b) => desc ? order[b] - order[a] : order[a] - order[b])
.reduce((acc, val) =>
acc.concat(array.filter(({ bar: { order }}) => val === order))
, []);
console.log('Descending order');
console.log(orderWith(foo, order));
console.log('Ascending order')
console.log(orderWith(foo, order, true));

Related

Inside an Object.value loop how can I get the key

I have to create match condition based on an array my array will look like below
var groupData={
A:[
{rollnum: 1, name:'Arya', age:15},
{rollnum: 2, name:'Aryan', age:15}
],
B:[
{rollnum:11, name:'Biba', age:15},
{rollnum:12, name:'Bimisha', age:15}
]
}
I am looping using for loop. How can reduce the loops. Can any one suggest me a proper way for this
Object.values(groupData).flat().forEach((rowitem)=>{
query={};
Object.keys(rowitem).forEach(eachField=>{
query[eachField]["$in"].push(rowitem[eachField])
});
fullarray[Object.keys(groupData)]=matchQuery;
})
I need an output (fullarray) like below
{
'A':{
rollnum:{'$in':[1,2]},
name: {'$in':['Arya', 'Aryan']},
age: {'$in':[15]}
},
'B':{
rollnum:{'$in':[11,12]},
name: {'$in':['Biba', 'Bimisha']},
age: {'$in':[15]}
}
}
Here 'A' 'B' is not coming correctly
Don't use Object.values() since that discards the A and B keys.
Use nested loops, one loop for the properties in the object, and a nested loop for the arrays.
You need to create the nested objects and arrays before you can add to them.
var groupData = { A:
[ { rollnum: 1,
name: 'Arya',
age:15},
{ rollnum: 2,
name: 'Aryan',
age:15}, ],
B:
[ { rollnum: 11,
name: 'Biba',
age:15},
{ rollnum: 12,
name: 'Bimisha',
age:15} ] }
result = {};
Object.entries(groupData).forEach(([key, arr]) => {
if (!result[key]) {
result[key] = {};
}
cur = result[key];
arr.forEach(obj => {
Object.entries(obj).forEach(([key2, val]) => {
if (!cur[key2]) {
cur[key2] = {
"$in": []
};
}
cur[key2]["$in"].push(val);
});
});
});
console.log(result);

lodash filter not finding value in multidimensional array of Shopify order

Looking to see if an order line_item has been refunded before processing...
Here is a single order:
var order = {
line_items: [
{
id: 1326167752753
}
],
refunds: [
{
refund_line_items: [
{
id: 41264152625,
line_item_id: 1326167752753,
}
]
}
]
};
Trying to log out the filter results:
console.log(
_.filter(order, {
refunds: [
{
refund_line_items: [
{
line_item_id: 1326167752753
}
]
}
]
}).length
);
I'm getting 0 on the console.
Am I using _.filter wrong in this case?
Function take needs an array (order is not an array, order.refunds is) and a predicate, not an object.
Anyway, I'd write it using Array.some:
const itemWasRefunded = order.refunds.some(refund =>
refund.refund_line_items.some(refund_line_item =>
refund_line_item.line_item_id === 1326167752753
)
);
Or, alternatively, getting all line_item_ids and checking inclusion:
const itemWasRefunded = _(order.refunds)
.flatMap("refund_line_items")
.map("line_item_id")
.includes(1326167752753);
You can use some and find and do this in lodash and also easily in ES6:
var order = { line_items: [{ id: 1326167752753 }], refunds: [{ refund_line_items: [{ id: 41264152625, line_item_id: 1326167752753, }] }] };
// lodash
const _searchRefunds = (lid) => _.some(order.refunds, x =>
_.find(x.refund_line_items, {line_item_id: lid}))
console.log('loadsh:', _searchRefunds(1326167752753)) // true
console.log('loadsh:', _searchRefunds(132616772323232352753)) // false
//es6
const searchRefunds = (lid) => order.refunds.some(x =>
x.refund_line_items.find(y => y.line_item_id == lid))
console.log('ES6:', searchRefunds(1326167752753)) // true
console.log('ES6:', searchRefunds(132616772323232352753)) // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Add array element during definition based on condition

I define an array like this:
[{foo:0}, true === false && { foobar:1}, {bar:2}]
My expected result would be that the middle item is not added at all when the middle condition is not met:
[ { foo: 0 }, { bar: 2 } ]
in fact it adds false as an array item:
[ { foo: 0 }, false, { bar: 2 } ]
Is there a way to prevent adding the false while maintaining this lightweight syntax (I know I could always use push or the spread operator)
You could use concat with spread syntax and an empty array as neutral value.
var a = [].concat(...[
{ foo: 0 },
true === false ? { foobar: 1 } : [],
{ bar: 2 }
]);
console.log(a);
With apply
var a = Array.prototype.concat.apply([], [
{ foo: 0 },
true === false ? { foobar: 1 } : [],
{ bar: 2 }
]);
console.log(a);
As Denys suggested, you could do this:
const arr = [{foo:0}, true === false && { foobar:1}, {bar:2}].filter(el => el !== false);
console.log(arr);

convert array value to an object value

How do I convert this array
[ { africa: 1 },
{ culture: 1 },
{ feminism: 3 },
{ 'feminists rising': 1 },
{ law: 1 } ]
into something like this
someObj = {africa: 1, culture: 1, feminism: 3, 'feminists rising': 1, law: 1}
Spread the array into Object#assign:
const data = [{"africa":1},{"culture":1},{"feminism":3},{"feminists rising":1},{"law":1}];
const result = Object.assign({}, ...data);
console.log(result);
const raw = [
{
africa: 1
},
{
culture: 1
},
{
feminism: 3
},
{
'feminists rising': 1
},
{
law: 1
}
];
console.log(raw.reduce((acc, next) => {
const key = Object.keys(next)[0];
acc[key] = next[key];
return acc;
}, {}));
const subjects = [
{africa: 1},
{culture: 1},
{feminism: 3},
{'feminists rising': 1},
{law: 1}
];
Use the Object.assign() method to mash a list of the individual objects into an empty array. In order to generate the list from the array of objects, the spread syntax (...) is used.
const obj = Object.assign({}, ...subjects);

ramdajs: locating items with an inner array that satisfies a spec

Given a structure like this:
[
{
documentType: { id: 4001 }
correspondence: [ { id: 1000 }, { id: 1010 } ]
},
{
documentType: { id: 102 }
correspondence: [ { id: 1000 } ]
},
{
documentType: { id: 101 }
correspondence: [ { id: 1001 } ]
}
]
I am trying to use ramda to find the indexes of the array where the inner correspondence array contains 1000.
I have tried this:
R.filter(R.where({ correspondence: R.any(R.where({ id: 1000 }))}))(data)
First you'll want a slight tweak to your predicate function, changing the inner R.where to R.propEq to allow comparison against a constant value rather than a function:
const pred = R.where({ correspondence: R.any(R.propEq('id', 1000))})
Then I have two examples of how you could approach this, both making use of R.addIndex to capture the index:
One using R.reduce to build up a list while testing each element:
const reduceWithIdx = R.addIndex(R.reduce)
const fn = reduceWithIdx((acc, x, i) => pred(x) ? R.append(i, acc) : acc, [])
fn(data) //=> [0, 1]
The second using R.map to embed the index in each element before filtering:
const mapWithIdx = R.addIndex(R.map)
const fn = R.pipe(
mapWithIdx(R.flip(R.assoc('idx'))),
R.filter(pred),
R.map(R.prop('idx'))
)
fn(data) //=> [0, 1]

Categories

Resources