Ramda - get ids from nested array of multiple objects - ramda.js

I am trying to get outgoingNodes IDs which are stored in array which is inside objects like in example below but I have no idea where to start...:
const nodes = {
"818": {
"id": "818",
"index": 1,
"outgoingNodes": [
"819"
],
},
"819": {
"id": "819",
"outgoingNodes": [
"820",
"821"
],
}
}
I would like to get an array of IDs as a result. Any help will be appreciated.

Get the values (sub objects), pluck the outgoingNodes arrays, and flatten to a single array:
const { pipe, values, pluck, flatten } = R
const fn = pipe(
values,
pluck('outgoingNodes'),
flatten
)
const nodes = {"818":{"id":"818","index":1,"outgoingNodes":["819"]},"819":{"id":"819","outgoingNodes":["820","821"]}}
const result = fn(nodes)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
Another option is to combine getting the outgoingNodes arrays, and flattening to a single array using R.chain with R.prop:
const { pipe, values, chain, prop } = R
const fn = pipe(
values,
chain(prop('outgoingNodes')),
)
const nodes = {"818":{"id":"818","index":1,"outgoingNodes":["819"]},"819":{"id":"819","outgoingNodes":["820","821"]}}
const result = fn(nodes)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

Related

Ramda: filtering an array against an array of items

I have a working function to filter the following array:
const arrayOne = [
{
node: {
caseStudyFields: {
filterTags: [
"Temperature control"
]
}
}
},
{
node: {
caseStudyFields: {
filterTags: null
}
}
},
{
node: {
caseStudyFields: {
filterTags: [
"Specialist manufacturing",
"Pharmaceuticals"
]
}
}
},
]
const arrayTwo = [
'Pharmaceuticals',
'Specialist manufacturing',
'Temperature control'
]
const fn = n => n.node.caseStudyFields.filterTags &&
n.node.caseStudyFields.filterTags.some(r => arrayTwo.includes(r))
return arrayOne.filter(fn)
This code works fine, but I wanted to convert it to Ramda (for fun). I've got so far in finding the path but I've become confused with the some and includes (any in Ramda?)
const filter = R.filter(
R.pipe(
R.path(['node', 'caseStudyFields', 'filterTags']),
)
);
return filter(arrayOne)
Use R.pathOr to get the value at the path, and return and empty array if it's null. This will prevent filter from erroring when encountering the null.
Use R.any (Ramda's equivalent to Array.some()) with R.includes, curried with the array of tags, to find matching items:
const { curry, filter, pipe, pathOr, any, includes, __ } = R
const filterByTags = curry((tags, arr) =>
filter(pipe(
pathOr([], ['node', 'caseStudyFields', 'filterTags']),
any(includes(__, tags))
))
(arr))
const arrayOne = [{"node":{"caseStudyFields":{"filterTags":["Temperature control"]}}},{"node":{"caseStudyFields":{"filterTags":null}}},{"node":{"caseStudyFields":{"filterTags":["Specialist manufacturing","Pharmaceuticals"]}}}]
const arrayTwo = ["Pharmaceuticals","Specialist manufacturing","Temperature control"]
const result = filterByTags(arrayTwo, arrayOne)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

Lodash: filter when I have nested array property?

Consider below example. I am using Lodash
"home":[
{
"data":{
"interests":["sports", "travel", "boxing"],
"city":["x", "y", "z"],
"name":"test1"
},
"count":["1", "2"],
"country":"CA"
},
{
"data":{
"interests":["painting", "travel", "dancing"],
"city":["a", "y", "b"],
"name":"test2"
},
"count":["1","3"],
"country":"US"
}
]
If I'll try the function on key value pair example :
_.find(home, ['data.country', 'US']); // It is returning me the 2nd object
requirement :
I want all the objects where data.interests is 'dancing'.
Tried :
_.find(home, ['data.interests', 'dancing']) // It is returning []
I have also tried filter(), where() and map but unable to get the complete object.
Thanks in advance.
You can use vanilla JS or lodash funcntions - Filter the array, and for each item check if the data.interests array includes the requested word.
Vanilla:
const home = [{"data":{"interests":["sports","travel","boxing"],"city":["x","y","z"],"name":"test1"},"count":["1","2"],"country":"CA"},{"data":{"interests":["painting","travel","dancing"],"city":["a","y","b"],"name":"test2"},"count":["1","3"],"country":"US"}]
const result = home.filter(o => o.data.interests.includes('dancing'))
console.log(result)
Lodash:
const home = [{"data":{"interests":["sports","travel","boxing"],"city":["x","y","z"],"name":"test1"},"count":["1","2"],"country":"CA"},{"data":{"interests":["painting","travel","dancing"],"city":["a","y","b"],"name":"test2"},"count":["1","3"],"country":"US"}]
const result = _.filter(home, o => _.includes(o.data.interests, 'dancing'))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

lodash filter deeply nested objects returning array of those objects

I'm trying to return an array of objects that are deeply nested in another array. Here is a sample object with arrays:
payment = {
"id": 1,
"tickets" = [{
"id": 1,
"ticketItems": [{item1}, {item2}, {item3}]
},
{"id": 2",
"ticketItems": [{item4}, {item5}, {item6}]
}]}
Using lodash I would like to return an array of just items 1-6 without the parent objects. I've tried:
var items = _.filter(payment.tickets, {'ticketItems'});
But that doesn't return an array of ticketItems. All the examples I've found use a condition like "id: 1", but I want all of the ticketItems, not just those matching a condition.
You can use Array.flatMap() (or lodash's _.flatMap()) and return the ticketItems from each tickets object:
const payment = {"id":1,"tickets":[{"id":1,"ticketItems":[{"item1":1},{"item2":2},{"item3":3}]},{"id":2,"ticketItems":[{"item4":4},{"item5":5},{"item6":6}]}]}
const result = payment.tickets.flatMap(o => o.ticketItems)
console.log(result)
And the same solution with lodash's _.flatMap():
const payment = {"id":1,"tickets":[{"id":1,"ticketItems":[{"item1":1},{"item2":2},{"item3":3}]},{"id":2,"ticketItems":[{"item4":4},{"item5":5},{"item6":6}]}]}
const result = _.flatMap(payment.tickets, 'ticketItems')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Using ramda to modify data in array

Input:
[
{
temp: "24",
date: "2019-10-16T11:00:00.000Z"
}
]
Output:
[[new date("2019-10-16T11:00:00.000Z").getTime(), 24]]
Got some annoying mutability problems if I do it in vanilla javascript.
Good case to use ramda.
Something like:
const convertFunc = ...
const convertArr = R.map(convertFunc)
const result = convertArr(arr);
I'm stuck. Any ideas what Ramda functions to use?
I'm not sure Ramda would add anything substantial. Especially if you can use parameter destructuring:
map(({temp, date}) => [new Date(date).getTime(), temp],
[{ temp: "24",
date: "2019-10-16T11:00:00.000Z"}]);
//=> [[1571223600000, "24"]]
You can map the array of objects, and use R.evolve to convert the date string to time via Date.parse(), and then get the R.props to convert to an array of arrays.
const { map, pipe, evolve, identity, props } = R
const fn = map(pipe(
evolve({ temp: identity, date: Date.parse }),
props(['date', 'temp'])
))
const data = [{temp: "24",date: "2019-10-16T11:00:00.000Z"}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Ramda, concat with propOr/pathOr

const obj = {
psets: [...],
type: {
psets: [...]
}
}
Want to concat the psets props. Both of them may not exist.
R.concat(R.pathOr([], ['type','pSets']), R.propOr([], 'pSets'));
**
Uncaught TypeError: function n(r){return 0===arguments.length||w(r)?n:t.apply(this,arguments)} does not have a method named "concat"
What am I doing wrong?
R.concat expects arrays or strings, and not functions. You can use R.converge to prepare the arrays for concat.
Note: R.__ is used as a placeholder for incoming arguments that you to assign to a different position than the last parameter.
const obj = {
pSets: [1, 2],
type: {
pSets: [3, 4]
}
}
const fn = R.converge(R.concat, [
R.pathOr([], ['type','pSets']),
R.propOr([], 'pSets')]
)
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Another option that will make the code DRYer is to use R.chain to iterate the paths, get the the values from the object, and concat them:
const obj = {
pSets: [1, 2],
type: {
pSets: [3, 4]
}
}
const fn = R.curry((paths, obj) => R.chain(R.pathOr([], R.__, obj), paths))
const result = fn([['pSets'], ['type','pSets']], obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>