Executing a list of functions on an array - javascript

I'm getting to grips with using functional programming beyond a simple map or two. I have a situation where I want to be able to filter some elements from an array of objects, based on a particular field of those objects. It's a contrived example, but here goes:
I have a list of field definitions, and I want to extract two of them based on their title.
const toSearch = [
{ title: "name", description: "Their name" },
{ title: "age", description: "Their age" },
{ title: "gender", description: "Their gender" }
]
const fieldsToFind = ["name", "age"]
let filterObjects = R.map(R.objOf('title'), fieldsToFind)
let filterFuncs = R.map(R.whereEq(R.__), filterObjects)
let found = R.map(R.filter, filterFuncs)
console.log("Filter objects:", JSON.stringify(filterObjects))
console.log("Filter functions:", JSON.stringify(filterFuncs))
console.log("Found:", found[0](toSearch))
console.log("Found:", found[1](toSearch))
If I run this, the last of the output is the two elements of toSearch that I'm looking for, but it's not exactly neat. I've been trying to get another map working to get around executing found elements manually, but I also feel that even leading up to that point I'm taking an overly circuitous route.
Although it's a contrived example, is there a neater way of accomplishing this in a functional style?

One fairly simple way of doing this is:
R.filter(R.where({R.title: R.contains(R.__, ['name', 'age'])}))(toSearch);
//=> [
// {"description": "Their name", "title": "name"},
// {"description": "Their age", "title": "age"}
// ]
or, equivalently,
R.filter(R.where({title: R.flip(R.contains)(['name', 'age'])}))(toSearch);
One advantage, especially if you import the relevant functions from R into your scope, is how closely this reads to your problem domain:
var myFunc = filter(where({title: contains(__, ['name', 'age'])}));
myFunc = filter where the title contains 'name' or 'age'.
You can see this in action on the Ramda REPL.

I have a situation where I want to be able to filter some elements
from an array of objects, based on a particular field of those
objects.
For your situation, its quite simple
var filteredItems = toSearch.filter(function(value){ return fieldsToFind.indexOf(value.title) != -1 });

You could use .reduce to accomplish your task. MDN has a very brief explanation of the reduce function

Related

Create Json with specific structure from two different arrays in javascript

I've already tried to find a solution on stack, but I didn't found a possible reply, so I decided to open a topic to ask:
Let's say we have 2 arrays: one containing "keys" and another one containing "values"
Example:
keys = [CO2, Blood, General, AnotherKey, ... ]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[... [
I have to create a Json with a specific structure like:
[{
name: 'CO2',
data: [2,5,4,6]
}, {
name: 'Blood',
data: [4,5,6]
}, {
name: 'General',
data: [1,3,34.5,43.4]
}, {
...
},
}]
I've tried to make some test bymyself, like concatenate strings and then encode it as json, but I don't think is the correct path to follow and a good implementation of it ... I've also take a look on JSON.PARSE, JSON.stringify, but I never arrived at good solution so... I am asking if someone know the correct way to implements it!
EDIT:
In reality, i didn't find a solution since "name" and "data" are no strings but object
Here's one way to get your desired output:
keys = ["CO2", "Blood", "General", "AnotherKey"]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[0] ]
const output = keys.map((x, i) => {
return {"name": x, "data": values[i]}
})
console.log(output)
However, since you're literally constructing key/value pairs, you should consider whether an object might be a better data format to output:
keys = ["CO2", "Blood", "General", "AnotherKey"]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[0] ]
const output = {}
for (let i=0; i<keys.length; i++) {
output[keys[i]] = values[i]
}
console.log(output)
With this data structure you can easily get the data for any keyword (e.g. output.CO2). With your array structure you would need to iterate over the array every time you wanted to find something in it.
(Note: The reason you weren't getting anywhere useful by searching for JSON methods is that nothing in your question has anything to do with JSON; you're just trying to transform some data from one format to another. JSON is a string representation of a data object.)

Converting a string to a list and seperate each element

So I have a use case in which I enter indexes and descriptions which belong to a round. I created a JS function that allows me to enter these indexes and descriptions. When I strip the data from the post request I get the following data:
['0,This is a testround', '1,This is a new testround']
I want to split this data so that I can seperate the 0 in an index variable and the following description "This is a testround" in a description variable. Please note that the description can only contain comma's. The indexes are not always corresponding with the indexes of an array: [[0,"Description1"],[5,"Description2"]] could happen
A possible solution could be to split the string on a comma and use str[0] for the index and the other parts for the description but to me this would look like an ugly solution.
What should I do?
I use the following JS to save the rounds to a playerdata div from which i extract the list above (in which items is the list with the index and description)
function item_checkbox(items,n) {
return `
<input type="checkbox" style="display:none;" name="${itemList[n]}" value="${items}" checked>
`
}
function add_to_itemData(items, n) {
itemDataEl = document.getElementById(itemData[n])
itemDataEl.innerHTML = itemDataEl.innerHTML + item_checkbox(items, n)
}
Thanks for any help in advance
While you say that it would be an "ugly" solution to solve it by splitting, I think it's a pretty straightforward routine, given the format the data is returned to you.
['0,This is a testround', '1,This is a new testround'].map(v => v.split(','));
... would translate correctly to:
[
[ "0", "This is a testround" ],
[ "1", "This is a new testround" ]
]
But I guess I get what you mean. There are a few possible problems - for example, that of key uniqueness. You could solve this one by keeping each row into Javascript objects instead of arrays, and you can convert it quite easily by using Object.fromEntries(), since it conveniently accepts each row of bidimensional arrays as key/value pairs:
Object.fromEntries([
[ "0", "This is a testround" ],
[ "1", "This is a new testround" ],
[ "1", "This is a dupe testround" ] // this will overwrite the previous entry
]);
// {0: "This is a testround", 1: "This is a dupe testround"}
You might want to take a few extra steps for additional control, like using .trim() to remove leading or trailing whitespaces or testing/filtering/splitting them using a custom regex.

Functional programming / Ramda: Creating a new object by picking nested properties

Functional programming newbie here. I have this object:
{
_id: '2014d5db-55dc-4078-ae87-382c226d0785',
_source: {
phone: '00447827434313',
...
}
}
In the end I want to have it in this format:
{
id: '2014d5db-55dc-4078-ae87-382c226d0785',
phone: '00447827434313',
...
}
Basically extracting _source, and renaming _id to id.
I created this function below which works, but I'm trying use only Ramda's functions instead of creating new objects by hand. I assume it's more "functional" way, let me know if it doesn't really matter.
const test = o => merge(o._source, { id: o._id })
Thanks very much
I don't think there's a particular built-in Ramda function for that. But it's not hard to write one on top of lensPath, view, and map:
const remap = R.curry((desc, obj) => R.map(path => R.view(R.lensPath(path), obj), desc));
const myExtract = remap({
id: ['_id'],
phone: ['_source', 'phone']
});
myExtract(input);
//=> {"id": "2014d5db-55dc-4078-ae87-382c226d0785", "phone": "00447827434313"}
It only works this simply if your output is described as a flat list of fields (of course their properties could themselves be objects.) But one where you pulled from nested paths and pushed to nested paths would not be too much harder to write. The user API would be uglier, though, I imagine.
I don't see any clean way to make this points-free and still retain readability. Perhaps someone else might manage that, but I think this is already pretty nice.
You can see this in action on the Ramda REPL.

Trying to return a deep nested object with Lodash

I have not been able to find a solution for this on StackoverlFlow and i have been working on this issue for some time now. Its a bit difficult so please let me know if i should provide more information.
My problem:
I have a JSON object of Lands, each land has an ID and a Blocks array associated with it and that blocks array has block with ID's too.
Preview:
var Lands = [{
'LandId':'123',
'something1':'qwerty',
'something2':'qwerty',
'Blocks': [
{
'id':'456',
'LandId':'123'
},
{
'BlockId':'789',
'LandId':'123'
}
]
},
...More Land Objects];
Note: The data is not setup the way i would have done it but this was done along time ago and i have to work with what i have for right now.
I am trying to write a lodash function that will take the blockId's that i have and match them and return the landId from the Blocks.
so the end result would be a list of LandId's that where returned from the Blocks.
I was using something like this and it was returning no results:
selectedLand = function(Lands, landIDs){
return _.filter(Lands, function(land){
return land === landIDs[index];
});
};
I know i am going about this the wrong way and would like to know the appropriate way to approach this and solve it. any help is much appreciated.
selectedLand = function(Lands, landIDs){
return _.filter(Lands, function(land){
return land === landIDs[index];
});
};
Note that index lacks any definition in this scope, so this function will essentially never return true, barring a lucky(?) accident with an externally defined index. And anytime you call _.filter(someArr,function(){return false;}) you'll get []. Undefined index aside, this does strict comparison of a land object against (maybe) a string in landIDs
I'm a bit unclear on the exact requirements of your selection, so you can tailor this filter to suit your needs. The function filters the lands array by checking if the .blocks array property has some values where the .landID property is included in the landsID array.
In closing, if you want to make the most out of lodash (or my favorite, ramda.js) I suggest you sit down and read the docs. Sounds deathly boring, but 75% of the battle with data transforms is knowing what's in your toolbox. Note how the English description of the process matches almost exactly with the example code (filter, some, includes).
var Lands = [{
'LandId': '123',
'something1': 'qwerty',
'something2': 'qwerty',
'Blocks': [{
'id': '456',
'LandId': '123'
}, {
'BlockId': '789',
'LandId': '123'
}]
}
];
// assuming lands is like the above example
// and landIDs is an array of strings
var selectLandsWithBlocks = function(lands, landIDs) {
return _.filter(lands, function(land) {
var blocks = land.Blocks;
var blockHasALandId = function(block) {
return _.includes(landIDs,block.LandId);
};
return _.some(blocks, blockHasALandId);
});
};
console.log(selectLandsWithBlocks(Lands,[]));
console.log(selectLandsWithBlocks(Lands,['mittens']));
console.log(selectLandsWithBlocks(Lands,['123']));
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>

Javascript function to count nested array of object properties possibly using reduce/map

I have a problem and I have looked at a few reduce questions on here and I just can't seem to wrap my head around a way to do this. I have an array of objects. Each object has the same properties, about 30 of them. Each of the properties has completely different types of information. I want to be able to create a new object/array easily. My example is below.
var array = [{parts: 12345, purchased: "yes", customerId: 12541},
{parts: 12432, purchased: "no", customerId: 55514},
{parts: 12345, purchased: "Yes", customerId: 44421}];
What I want to do is find a way to extract useful data depending on the type of information in the array. For example:
some_function(array) {
...
return { parts: {uniquePart: 12345, timesListed: 2}};
}
}
I may also want to extend that returned object and count the number of times purchased was either yes or no. I have tried numerous approaches but I am thinking this is more a data model issue than a programming issue.
I am parsing this data off of strings of receipts. Once the plain text string is parsed I get a large 30 property object for each transaction. Some of the properties also are nested objects or arrays as well.
I want to correlate data across multiple transactions. Maybe I need to research a better way to approach this type of situation as a whole.
So I understand the question is a little vague but what I really want to know is what is the best way with the array given to end up with the following data structure:
{parts: {uniquePart: 12345, timeListed 2}}
I believe once I understand how to itterate through the nested array of objects and build the new object I can go from there. My current attempts using reduce have not yielded fruit.
array.reduce(acc,obj){return This is where I am a little lost}
This solution features Array.prototype.forEach, Object.keys and Array.prototype.map for a temporary object count and returns the wanted array with one object for every part.
function getCount(array) {
var count = {};
array.forEach(function (a) {
count[a.parts] = (count[a.parts] || 0) + 1;
});
return Object.keys(count).map(function (k) {
return { parts: { uniquePart: k, timesListed: count[k] } };
});
}
var array = [{ parts: 12345, purchased: "yes", customerId: 12541 }, { parts: 12432, purchased: "no", customerId: 55514 }, { parts: 12345, purchased: "Yes", customerId: 44421 }];
document.write('<pre>' + JSON.stringify(getCount(array), 0, 4) + '</pre>');

Categories

Resources