How to group by a key and sum other keys with Ramda? - ramda.js

Suppose I have an array of objects like this:
[
{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45},
{'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10},
{'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5},
{'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}
]
I would like to group by the first property and sum the values of the other properties, resulting in an array like this:
[
{'prop_1': 'key_1', 'prop_2': 79, 'prop_3': 55},
{'prop_1': 'key_2', 'prop_2': 16, 'prop_3': 12}
]
What is the correct way to do this using Ramda?
I have attempted to use the following:
R.pipe(
R.groupBy(R.prop('prop_1')),
R.values,
R.reduce(R.mergeWith(R.add), {})
)
But this sums also the value of 'prop_1'.

You'll need to map the groups, and then reduce each group. Check the values of the currently merged keys. If the value is a Number add the values. If not just return the 1st value:
const { pipe, groupBy, prop, values, map, reduce, mergeWith, ifElse, is, add, identity } = R
const fn = pipe(
groupBy(prop('prop_1')),
values,
map(reduce(
mergeWith(ifElse(is(Number), add, identity)),
{}
))
)
const data = [{"prop_1":"key_1","prop_2":23,"prop_3":45},{"prop_1":"key_1","prop_2":56,"prop_3":10},{"prop_1":"key_2","prop_2":10,"prop_3":5},{"prop_1":"key_2","prop_2":6,"prop_3":7}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

If and only if you know the keys in advance, you could opt for something "simpler" (of course YMMV):
reduceBy takes a function similar to Array#reduce
Use prop('prop_1') as a "group by" clause
(It should be relatively straightforward to extract the values out of the object to get the final array.)
console.log(
reduceBy
( (acc, obj) =>
({ prop_1: obj.prop_1
, prop_2: acc.prop_2 + obj.prop_2
, prop_3: acc.prop_3 + obj.prop_3
})
// acc initial value
, { prop_1: ''
, prop_2: 0
, prop_3: 0
}
// group by clause
, prop('prop_1')
, data
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.min.js"></script>
<script>const {reduceBy, prop} = R;</script>
<script>
const data = [{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45}, {'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10}, {'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5}, {'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}];
</script>

This answer is not as simple as that from Ori Drori. And I'm not sure whether that's a good thing. This seems to more closely fit the requirements, especially if "and sum the values of the other properties" is a simplification of actual requirements. This tries to keep the key property and then combine the others based on your function
const data = [
{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45},
{'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10},
{'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5},
{'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}
]
const transform = (key, combine) => pipe (
groupBy (prop (key)),
map (map (omit ([key]))),
map (combine),
toPairs,
map (([key, obj]) => ({prop_1: key, ...obj}))
)
console .log (
transform ('prop_1', reduce(mergeWith (add), {})) (data)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {pipe, groupBy, prop, map, omit, reduce, mergeWith, add, toPairs, lift, merge, head, objOf, last} = R </script>
If you have a fetish for point-free code that last line could be written as
map (lift (merge) (pipe (head, objOf(key)), last))
But as we are already making points of key and obj, I see no reason. Yes, we could change that, but I think it would become pretty ugly code.
There might well be something to be said for a more reduce-like version, where instead of passing such a combine function, we pass something that combines two values as well as a way to get the initial value. That's left as an exercise for later.

Related

How input data in line chart in Pentaho?

I want to make this chart in Pentaho CDE:
based in this chart (I think that is the most similar from among CCC Components):
(The code is in this link.)
but I don't know how I can adapt my data input to that graph.
For example, I want to consume the data with this format:
[Year, customers_A, customers_B, cars_A, cars_B] [2014, 8, 4, 23, 20]
[2015, 20, 6, 30, 38]
How I can input my data in this chart?
Your data should come as an object such as this:
data = {
metadata: [
{ colName: "Year", colType:"Numeric", colIndex: 1},
{ colName: "customers_A", colType:"Numeric", colIndex: 2},
{ colName: "customers_B", colType:"Numeric", colIndex: 3},
{ colName: "cars_A", colType:"Numeric", colIndex: 4},
{ colName: "cars_B", colType:"Numeric", colIndex: 5}
],
resultset: [
[2014, 8, 4, 23, 20],
[2015, 20, 6, 30, 38]
],
queryInfo: {totalRows: 2}
}

How to turn a pandas pivot_table into a simple table

I have a simple DataFrame defined by:
df = pd.DataFrame({
'year': [2019, 2020, 2019, 2020, 2019, 2020, 2019, 2020],
'name': ['Alice', 'Alice', 'Alice', 'Alice', 'Bob', 'Bob', 'Bob', 'Bob'],
'sales': [100, 200, 300, 400, 500, 600, 700, 800]
})
This DataFrame is easily turned into a pivot table using pivot_table :
table = pd.pivot_table(
df,
index=['name'],
columns=['year'],
aggfunc=np.sum)
Now I need to turn this DataFrame into a simple JSON array. Unfortunately, the to_json method doesn't return a simple array:
table.reset_index().to_json(orient="records")
[
{
"["name",""]":"Alice",
"["sales",2019]":400,
"["sales",2020]":600
},
{
"["name",""]":"Bob",
"["sales",2019]":1200,
"["sales",2020]":1400}
]
How can I turn the table DataFrame into a simple (without multiindex) DataFrame?
[
{
"name":"Alice",
"2019":400,
"2020":600
},
{
"name":"Bob",
"2019":1200,
"2020":1400
}
]
you need to pass the values param to get rid of the multiindex , also get rid of the lists in the param inside pivot when passing a single column:
table = pd.pivot_table(
df,
index='name',
columns='year',
values='sales',
aggfunc=np.sum)
table.reset_index().to_json(orient="records")
'[{"name":"Alice","2019":400,"2020":600},{"name":"Bob","2019":1200,"2020":1400}]'
Adding another alternative if you like:
out = (df.groupby(['name','year'])['sales'].sum().unstack()
.reset_index().to_json(orient='records'))
'[{"name":"Alice","2019":400,"2020":600},{"name":"Bob","2019":1200,"2020":1400}]'

Check if the value of key in an array of objects is same - Lodash

Want to check if either the values of all rows in the array of objects is same or the values of all columns in the array of objects is same. How do I efficiently do this with lodash?
[
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2}
]
In the above case all rows in the array of objects is same.
If I understood the constraints correctly, how about this?
var data = [
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2},
];
function allTheSame(data, key) {
return data.length && _.every(data, function (item) {
return item[key] === data[0][key];
});
}
console.log(_.any(['row', 'col'], function (key) {
return allTheSame(data, key);
}));
Note that _.every and _.any both bail out early, so this should be about as efficient as possible.
Also note that allTheSame returns false if there are no elements in the array. You could switch to return data.length === 0 || _.every(... instead if you want an empty list to be considered "all the same."
The tricky part is trying to check if both column or row values are the same, in the same iteration with lodash. However, that shouldn't be necessary unless your are dealing with an unspeakable amount of data. Assuming that is not the case, here's simple, linear approach:
function isRowOrColSame(data) {
var row = _.every(data, {'row': data[0].row})
var col = _.every(data, {'col': data[0].col})
return (row || col)
}
var data = [
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2}
]
console.log(isRowOrColSame(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
If you need an explanation as to what's going on with the every function, let me know. I hope that helps!

Swift: for-in with two values

I started learning C some weeks ago and today I started learning Swift. The code is the following:
import Foundation
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
var largest = 0;
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
}
}
}
println(largest);
Why do I need kind in the for-in thingy? For "Prime", "Square", ..., right? Can I work with that somehow, too?
“Add another variable to keep track of which kind of number was the largest, as well as what that largest number was.”
How do I build that in?
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind)");
That's my solution at the moment. However, the output is
The number 25 is from the type Optional("Square")
How do I get rid of the 'Optional("")? I just want the word Square. I tried removing the question mark (var largestKind: String?; to var largestKind: String;) but I get an error doing that.
For those who have the same question, this is another solution I've found. var largestKind is still optional because of String? but the exclamation mark at the end \(largestKind!) makes it possible to access the value without having that optional stuff around the actual content.
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind!).");

Change the colour of bubbles in Google visualization motion chart

I there a way where by I can define the colours of bubbles in a motion chart provided by Google visualization API ? I do not want to use the default colour scheme.
Thank you in advance.
I've not found an inbuilt way to do this. However, what you can do is assign each bubble a "colour" variable. Then you can set the colour of the bubbles to this variable. I have found that for 3 bubbles, setting one to 1, another to 1.5 and the third to 3 projects reasonable well (on the default colour scheme, yellow projects very poorly). This approach gives you limited control over the colour scheme.
It's 2017 and I have yet to find a good update for this. So here is the solution I came up with. HTH.
#views.py
# Bubble Chart: ID, X, Y Color, Size
data.append(['ID', 'X', 'Y', 'Category', 'Z'])
data.append(['', 0, 0, 'Cat 1', 0]) #<-- the order of
data.append(['', 0, 0, 'Cat 2', 0]) #<-- these fakeout items
data.append(['', 0, 0, 'Cat 3', 0]) #<-- is important
data.append(['', 0, 0, 'Cat 4', 0]) #<-- Blue, Red, Orange, Green - in that order
... for r in source:
data.append(r.a, r.b, r.c, r.d, r.e)
return render(
request,
'Template.html',
{
'title':'',
'year':datetime.now().year,
'org': org,
'data': json.dumps(data),
}
#in the scripts block of template.html
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable({{data|safe}});
var options = {
title: 'Bubble By Category Strategy',
hAxis: { title: 'X', ticks: [{v: 0, f:''}, {v: 1, f:'L'}, {v: 2, f:'M'}, {v: 3, f:'H'}, {v: 4, f:''}] },
vAxis: { title: 'Y', ticks: [{v: 0, f:''}, {v: 1, f:'L'}, {v: 2, f:'M'}, {v: 3, f:'H'}, {v: 4, f:''}] },
bubble: {
textStyle: {
fontSize: 11,
fontName: 'Lato',
}
}
};
var chart = new google.visualization.BubbleChart(document.getElementById('riskChart'));
chart.draw(data, options);
}
</script>