Reducing to list of object from object key and value - ramda.js

Given a previous Ramda groupBy to
{
'2018-Q4': 2,
'2019-Q1': 5
}
How can I map this to
[
{'quarter': '2018-Q4', 'value': 2},
{'quarter': '2019-Q1', 'value': 5},
]

Convert to pairs and then zipObj with the field names:
const { pipe, toPairs, map, zipObj } = R
const fn = pipe(
toPairs,
map(zipObj(['quarter', 'value']))
)
const data = {
'2018-Q4': 2,
'2019-Q1': 5
}
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

Related

what should i use istead of ans if i want to make a list?

what should i use istead of ans if i want to make a list? I tried putting more ans var but it doesn't work only displays the last ans
<script setup>
import { ref } from "#vue/reactivity";
const faqToggle = ref(false);
const faqItems = ref([
** {
title: "test",
ans: "· test1",
id: 1,
},**
]);
const id = ref(null);
const toggle = (fid) => {
if (fid === id.value) {
faqToggle.value = !faqToggle.value;
} else {
faqToggle.value = true;
}
id.value = fid;
};
</script>
title: "test",
ans: "· test1",
ans: "· test2",
ans: "· test3",
ans: "· test4",
id: 1,

How to merge objects with Lodash, but replace arrays values?

I'm trying to replace arrays of an old object with values from a new object which has arrays... I guess it will make sense when you see an example and desire result:
https://jsfiddle.net/redlive/9coq7dmu/
const oldValues = {
a: 1,
b: [2, 21, 22, 23],
c: {
d: 3,
e: 4,
f: [5, 6, 7]
}
};
const updatedValues = {
b: [],
c: {
f: [8]
}
}
const result = _.merge( oldValues, updatedValues );
console.log(result);
/* Desire result:
{
a: 1,
b: [],
c: {
d: 3,
e: 4,
f: [8]
}
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
Use _.mergeWith(), and if the 2nd value is an array, return it. If not return undefined, and let merge handle it:
const oldValues = {"a":1,"b":[2,21,22,23],"c":{"d":3,"e":4,"f":[5,6,7]}};
const updatedValues = {"b":[],"c":{"f":[8]}};
const result = _.mergeWith(oldValues, updatedValues, (a, b) =>
_.isArray(b) ? b : undefined
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

Ramda, filter with or condition

let arr = [
{
name: 'Anna',
q: {
name: 'Jane'
}
}
];
const getName = R.prop('name');
const getQname = R.path(['q','name']);
A filter where any of these two functions passes.
Something like:
export const filterByName = (name) =>
R.filter(
R.or(
R.propEq(getName, name),
R.propEq(getQname, name)
)
)
Not working. How can I combine these two functions in a R.filter?
Use R.either with R.propEq for the name and R.pathEq from q.name:
const filterByName = (name) =>
R.filter(
R.either(
R.propEq('name', name),
R.pathEq(['q', 'name'], name)
)
)
const arr = [{"name":"Anna","q":{"name":"Jane"}},{"name":"Smite","q":{"name":"Jane"}},{"name":"Another","q":{"name":"One"}}];
console.log(filterByName('Anna')(arr))
console.log(filterByName('Jane')(arr))
console.log(filterByName('XXX')(arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
If you want to use an external function to extract the values, you can use R.pipe. Extract all property values with R.juxt, and then use R.any with R.equal to check for equality.
const getName = R.prop('name');
const getQname = R.path(['q','name']);
const filterByName = (name) =>
R.filter(
R.pipe(
R.juxt([getName, getQname]), // get all names
R.any(R.equals(name)) // check if any of the equals to name
)
)
const arr = [{"name":"Anna","q":{"name":"Jane"}},{"name":"Smite","q":{"name":"Jane"}},{"name":"Another","q":{"name":"One"}}];
console.log(filterByName('Anna')(arr))
console.log(filterByName('Jane')(arr))
console.log(filterByName('XXX')(arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
I would use either as it works with functions:
export const filterByName = (name) =>
R.filter(R.either(
R.propEq('name', name),
R.pathEq(['q', 'name'], name)));
or
const nameIs = R.propEq('name');
const qNameIs = R.pathEq(['q','name']);
export const filterByName = (name) =>
R.filter(R.either(nameIs(name), qNameIs(name)));
You could also write this in a point free style:
const nameIs = R.converge(R.or, [
R.pathEq(['name']),
R.pathEq(['q', 'name']),
]);
const onlyAnna = R.filter(nameIs('Anna'));
const onlyGiuseppe = R.filter(nameIs('Giuseppe'));
const data = [
{ name: 'Anna', q: { name: 'Jane' } },
{ name: 'Mark', q: { name: 'Mark' } },
{ name: 'Giuseppe', q: { name: 'Hitmands' } },
];
console.log('Anna', onlyAnna(data));
console.log('Giuseppe', onlyGiuseppe(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

custom sum elements by key using lodash

I do have two objects containing keys like
var a = {bar:[1,2], foo:[7,9]}
var b = {bar:[2,2], foo:[3,1]}
I want to get the fallowing results:
var c = {bar:[3,4], foo:[10,10]}
I already have a for logic like:
for (let key in b) {
if (a[key]) {
a[key][0] += b[key][0];
a[key][1] += b[key][1];
}
else a[key] = b[key];
}
But I would like to make this logic in a lodash way. How can I Do it?
You can use create a function that takes n objects, and collects them to an array using rest parameters. Now you can spread the array into _.mergeWith() to combine the objects, and in the customizer function sum the items in the arrays using Array.map() or lodash's _.map() and _.add():
const { mergeWith, isArray, map, add } = _
const fn = (...rest) => _.mergeWith({}, ...rest, (o = [], s) =>
map(s, (n, i) => add(n, o[i]))
)
const a = {bar:[1,2], foo:[7,9]}
const b = {bar:[2,2], foo:[3,1]}
const c = {bar:[3,2], foo:[5,6]}
const d = {bar:[4,2], foo:[5,4]}
const result = fn(a, b, c, d)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You can also use lodash/fp to create a function that merges all values to a multidimensional array with _.mergeAllWith(), then transpose the arrays using _.zipAll(), and sums each array:
const { rest, flow, mergeAllWith, isArray, head, mapValues, zipAll, map, sum } = _
const fn = rest(flow(
mergeAllWith((o, s) => [...isArray(head(o)) ? o : [o], s]), // combine to a multidimensional array
mapValues(flow(
zipAll,
map(sum)
)),
))
const a = {bar:[1,2], foo:[7,9]}
const b = {bar:[2,2], foo:[3,1]}
const c = {bar:[3,2], foo:[5,6]}
const d = {bar:[4,2], foo:[5,4]}
const result = fn(a, b, c, d)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You can accomplish this using plain JavaScript with Object.entries, concat and reduce:
const a = { bar: [1,2], foo: [7,9] };
const b = { bar: [2,2], foo: [3,1] };
const entries = Object.entries(a).concat(Object.entries(b));
const result = entries.reduce((accum, [key, val]) => {
accum[key] = accum[key] ? accum[key].map((x, i) => x + val[i]) : val;
return accum;
}, { });
console.log(result);

How group and count elements by lodash

has data
items = {
0: {id:1,name:'foo'},
1: {id:2,name:'bar'},
2: {id:1,name:'foo'}
};
I wont get counted elements like this
result = {
0: {id:1,name:'foo', count:2},
1: {id:2,name:'bar', count:1}
};
lodash has function _.countBy(items, 'name') it's got {'foo': 2, 'bar':1}, i need id too.
If pure JS approach is acceptable, you can try something like this:
Logiic:
Loop over array and copy the object and add a property count and set it to 0.
Now on every iteration update this count variable.
Using above 2 steps, create a hashMap.
Now loop over hashMap again and convert it back to array.
var items = [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}, {
id: 1,
name: 'foo'
}
];
var temp = items.reduce(function(p,c){
var defaultValue = {
name: c.name,
id: c.id,
count: 0
};
p[c.name] = p[c.name] || defaultValue
p[c.name].count++;
return p;
}, {});
var result = [];
for( var k in temp ){
result.push(temp[k]);
}
console.log(result)