lodash transform object with array to array of objects - lodash

Using a lodash, I want to transform an object that contains array into array of objects. here is an example:
Original object :
[
{
name:"name1"
params: [{param: "value1"}, {param: "value2"}]
},
{
name:"name2"
params: [{param: "value3"}, {param: "value4"}]
}
]
After transformation:
[
{name:"name1", param: "value1"},
{name:"name1", param: "value2"},
{name:"name2", param: "value3"},
{name:"name2", param: "value4"}
]
Whats the easiest way to achieve this ? Thanks
[EDIT]
Till now I implemented the function below, but I'm almost sure there must be more elegant solution for my problem.
transform (res) {
const data = [];
_.each(res, (obj) => {
const params = _.pick(obj, ['params']);
const withoutParams = _.omit(obj, 'params');
_.each(params.params, (param) => {
data.push(_.assign(param, withoutParams));
});
});
console.log('data', data);
return data
}

You can _.map() the params and the name of each object into an array of objects, and then _.flatMap() all objects arrays into one array:
var arr = [
{
name:"name1",
params: [{param: "value1"}, {param: "value2"}]
},
{
name:"name2",
params: [{param: "value3"}, {param: "value4"}]
}
];
var newArr = _.flatMap(arr, function(obj) {
return _.map(obj.params, function(param) {
return {
name: obj.name,
param: param.param
};
});
});
console.log(newArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
And this is the ES6 version using Array.prototype.map(), arrow functions, and destructuring:
const arr = [
{
name:"name1",
params: [{param: "value1"}, {param: "value2"}]
},
{
name:"name2",
params: [{param: "value3"}, {param: "value4"}]
}
];
const newArr = _.flatMap(arr, ({
name, params
}) => params.map(({
param
}) => ({
name, param
})));
console.log(newArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Related

this.state return empty array when render

I wanted to display the array series and when I tried to console the array this.state.series in the function it does has the result and the value inside but when I render this.state.series just keep giving empty array. I wonder is it because of the componentDidMount()?
constructor(props){
super(props);
this.state={series:[]}
}
GetTransaction=()=> {
var APIURL="http://10.0.2.2:80/api/getTransaction.php";
var headers={
'Accept':'application/json',
'Content-Type':'application.json'
}
fetch(APIURL,
{
method:'POST',
headers: headers,
})
.then((response)=>response.json())
.then((response)=>
{
this.setState({results:response});
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
console.log(this.state.series)
})
.catch((error)=>
{
alert("Error"+error);
}
)
}
componentDidMount(){ // runs after the component output has been rendered to the DOM
this.GetTransaction();
}
render(){
console.log(this.state.series)
output
Array []
Array []
Array []
Array []
Array []
Array []
Array []
Array [
"1",
"2",
"1",
"1",
]
There are basically 2 errors in GetTransaction state assignment:
you can't read a state just assigned because this.setState is async. If you want to get the very last value of state you should use this.setState's callback:
this.setState({results:response}, () => {
console.log(this.state.result); //<-- here you have the very last value of result
});
state must be always setted with this.setState: this.state.series.push(a.count) is not good.
So you have to rewrite your code in this way:
...
this.setState({results:response}, () => {
let seriesAppo = [];
this.state.results[0].map((a) => {
seriesAppo.push(a.count);
});
this.setState({series: seriesAppo}, () => {
console.log(this.state.series);
})
});
...
That‘s weird
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
Don‘t manipulate state that way, only with setState.
const series = response[0];
this.setState({series: series});
Even if you wanna add elements to an array you have to recreate the array. You can achieve this as follows:
const series = response[0];
this.setState({series: […this.state.series, …series]});

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>

Using Ramda to accumulate sum of values in objects

I have an object like this:
obj = {
'key1': {'prop1': 123,'prop2':345},
'key2': {'prop1': 673,'prop3':642}
}
I would like to have the following result:
result = {'prop1': 796, 'prop2':345, 'prop3':642}
That is, I want a single object that has all properties. I have a function like this:
Object.values(obj).reduce((acc,currentObj) => {
const props = Object.keys(currentObj);
props.forEach(prop => {
if(prop in acc){
acc[prop] += currentObj[prop]
} else {
acc[prop] = currentObj[prop]
}
})
return acc
}, {})
I believe this works fine, but is there any way to do the same with RamdaJS?
A simple reduce function would do that.
const fn = R.pipe(
R.values,
R.reduce(R.mergeWith(R.add), {}),
);
//--
const data = {
key1: { prop1: 123, prop2: 345 },
key2: { prop1: 673, prop3: 642 },
};
console.log(
fn(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

Filter data using lodash

How can filter the data with some inner attribute value.
updated_id='1234';
var result= _.map(self.list, function (item) {
// return only item.User_Info.id=updated_id
});
You can use the lodash#matchesProperty variant of lodash#filter to filter out objects that you need using the path of the property. The variant is in the 3rd example of the lodash#filter documentation.
var result = _.filter(self.list, ['User_Info.id', updated_id]);
var self = {
list: [
{ User_Info: { id: '4321' } },
{ User_Info: { id: '4321' } },
{ User_Info: { id: '1234' } },
{ User_Info: { id: '3214' } },
{ User_Info: { id: '2143' } }
]
};
var updated_id = '1234';
var result = _.filter(self.list, ['User_Info.id', updated_id]);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
lodash has a filter method:
const updated_id='1234';
const result= _.filter(self.list, item => item.User_Info.id === updated_id);
Use lodash _.filter method:
_.filter(collection, [predicate=_.identity])
Iterates over elements of collection, returning an array of all elements predicate returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).
with predicate as custom function
_.filter(myArr, function(o) {
return o.name == 'john';
});
with predicate as part of filtered object (the _.matches iteratee shorthand)
_.filter(myArr, {name: 'john'});
with predicate as [key, value] array (the _.matchesProperty iteratee shorthand.)
_.filter(myArr, ['name', 'John']);

Trouble getting m.request to auto-cast to a class in Mithril

I have defined a class and am asking m.request to cast a web service's JSON response to it, but each of the class properties come out equal to n/b(), and my view renders each property as function (){return arguments.length&&(a=arguments[0]),a}.
If I do not attempt to auto-cast the JSON response to my class in m.request, then my view renders just fine, which I think tells me that the JSON object returned by the web service is valid JSON.
I want to use my class. What is wrong?
Here is an edited sample of the JSON returned by the web service:
{
"responseHeader":{
"status":0,
"QTime":0,
"params":{
"q":"blah blah",
"indent":"true",
"wt":"json"}
},
"response":{
"numFound":97,
"start":0,
"docs":[
{
"identifier":"abc123",
"heading":"A Great Heading",
"id":"abc-123-1",
"title":"A Title",
"url":"path/to/some.html",
"content":["Blah blah blah blah blee blah."]
},
{
"identifier":"xyz789",
"heading":"Another Heading",
"id":"xyz-789-1",
"title":"Another Title",
"url":"another/path/to.html",
"content":["My bonny lies over the ocean."]
}
]
}
}
Here is my Mithril app:
var findus = {};
findus.Document = function (data) {
this.id = m.prop(data.id);
this.title = m.prop(data.title);
this.heading = m.prop(data.heading);
this.identifier = m.prop(data.identifer);
this.url = m.prop("//" + data.url + "#" + data.identifier);
};
findus.vm = (function() {
var vm = {};
vm.init = function () {
// user input
vm.queryText = m.prop("");
vm.search = function () {
if (vm.queryText()) {
vm.results = m.request({
method: "GET",
url: "/prd/query?q=" + vm.queryText(),
type: findus.Document,
unwrapSuccess: function (response) {
return response.response.docs;
},
unwrapError: function (response) {
console.log(response);
}
}).bind(vm);
}
};
};
return vm;
}());
findus.controller = function () {
findus.vm.init();
};
findus.view = function () {
return [
m("input", {onchange: m.withAttr("value", findus.vm.queryText), value: findus.vm.queryText()}),
m("button", {onclick: findus.vm.search}, "Search"),
findus.vm.results ? m("div", [
findus.vm.results().map(function (result) {
return m("div", [
m("h2", result.heading),
m("p", result.content),
m("a", {href: result.url}, result.url)
]);
})
]) : ""
];
};
m.module(document.body, {controller: findus.controller, view: findus.view});
Oh, bugger. I forgot that my class properties are getter/setters via m.prop, so I should have been calling them as functions in the view -- see below.
False alarm, problem solved, I'm embarrassed.
findus.view = function () {
return [
m("input", {onchange: m.withAttr("value", findus.vm.queryText), value: findus.vm.queryText()}),
m("button", {onclick: findus.vm.search}, "Search"),
findus.vm.results ? m("div", [
findus.vm.results().map(function (result) {
return m("div", [
m("h2", result.heading()),
m("p", m.trust(result.content())),
m("a", {href: result.url()}, result.url())
]);
})
]) : ""
];
};