In Rust is there a simple way to split a vector like this:
let original_vec = vec![
(14, "Foo", 62.3),
(17, "Foo", 77.8),
(25, "Bar", 33.7),
(27, "Bar", 99.2),
(61, "Foo", 17.4),
(64, "Bar", 55.5),
(77, "Bar", 31.2),
];
into this:
let res = vec![
vec![
(14, "Foo", 62.3),
(17, "Foo", 77.8),
],
vec![
(25, "Bar", 33.7),
(27, "Bar", 99.2),
],
vec![
(61, "Foo", 17.4), // "Foo" again
],
vec![
(61, "Bar", 55.5), // A separate group of "Bars"
(77, "Bar", 31.2),
],
]
Just to clarify: I want to split my input vector by one of the fields in its elements. Only contiguous elements with the same field value must be put in a sub-vector. The "flattened" result vector must have the same order as the original vector.
I found exactly what I was looking for:
original_vec.group_by(|a, b| a.1 == b.1)
However, the group_by method is only available in Nightly at the moment of writing this and requires adding:
#![feature(slice_group_by)]
As an alternative, as Sebastian suggested, group_by() from the itertools crate could be used.
Basically I imagine the following solution
let original_vec = vec![
(14, "Foo", 62.3),
(17, "Foo", 77.8),
(25, "Bar", 33.7),
(27, "Bar", 99.2),
(61, "Foo", 17.4),
(64, "Bar", 55.5),
(77, "Bar", 31.2),
];
type DATA = (i32, &'static str, f32);
let mut t: Vec<Vec<DATA>> = Vec::new();
let mut q: Vec<DATA> = Vec::new();
let mut p: DATA = (0, "", 0.0);
for i in original_vec
{
if i.1 != p.1 && p.1 != "" {
t.push(q);
q = Vec::new();
q.push(i);
}
q.push(i);
p = i;
}
println!("{:?}", t);
Related
I want to get from a data.table like this
temp <- data.table(data = list(data.table(a = 1:2,b=1:2)), type = "A")
data
type
<data.table[2x2]>
A
to a JSON like this
{
"group":
{
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "A"
}
}
The Problem is I always end up with an additional array "[" for group.
What I have tried is tidyr::nest and
temp2 <- temp[, list(group=list(.SD))]
jsonlite::toJSON(temp2,pretty = TRUE, auto_unbox = TRUE)
temp3 <- temp[, (list(group=list(as.list(.SD))))]
jsonlite::toJSON(temp3,pretty = TRUE, auto_unbox = TRUE)
Is there an "easy" solution for my problem?
Thanks
edit more complex example
temp <-
data.table(
id1 = 1:6,
id2 = c(rep("A", 2), rep("B", 2), rep("C", 2)),
data = rep(list(data.table(
a = 1:2, b = 1:2
)), 6),
type = "test"
)
nest1 <- temp[, list(list(.SD)),by=.(id1,id2)] %>% setnames("V1","group")
nest1[, type:="B"]
nest2 <- nest1[, list(list(.SD)),by=.(id2)] %>% setnames("V1","data")
nest2[, type:="C"]
nest3 <- nest2[, list(list(.SD)),by=.(id2)] %>% setnames("V1","group")
jsonlite::toJSON(nest3, pretty = TRUE)
desired output (shortend):
Group should only contain objects and no arrays
[
{
"id2": "A",
"group": {
"data": [
{
"id1": 1,
"group": {
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
},
"type": "B"
},
{
"id1": 2,
"group": {
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
},
"type": "B"
}
],
"type": "C"
}
},
{
"id2": "B",
"group": {
"data": [],
"type": "C"
}
}
]
We could use jq to do the unboxing as a post-processing step, since jsonlite doesn't seem to allow for this specific use case:
jsonlite::toJSON(nest3, pretty = TRUE) %>%
jqr::jq('walk(if type=="array" and length==1 then .[0] else . end)')
The jq bit is taken from jq ~ is there a better way to collapse single object arrays?
Is it possible to reproduce a meta-analysis type of flowchart as the one in the picture below using any R tool?
My attempt was using mermaid:
diagram = "
graph LR
subgraph Screening
b1-->b2
end
subgraph Eligibility
c1-->c2
end
subgraph Included
d1-->d2
end
subgraph Identification
a1-->a2
end
"
mermaid(diagram)
Which generated:
But I cannot find a way of connect the nodes accross the subgraphs.
Is there another tool better fitting to this kind of job? I am thinking on any package that I could use from within my Rmarkdown document.
I have found the DiagrammeR package easiest to do this. The general idea would be something like:
library(glue)
library(DiagrammeR)
excluded <- glue('Full text articles excluded
n = 1000
Reasons for exclusion
Reason 1
Reason 2')
grViz("
digraph cohort_flow_chart
{
node [fontname = Helvetica, fontsize = 12, shape = box, width = 4]
a[label = 'Records identified in original search']
b[label = 'Records identified with update']
c[label = 'Records after duplicates removed']
d[label = 'Records screened']
e[label = 'Records excluded']
f[label = 'Full text articles assessed']
g[label = 'Studies included']
h[label = '##1']
{ rank = same; a b}
{ rank = same; d, e}
{ rank = same; f, h}
a -> c;
b -> c;
c -> d;
d -> e [ minlen = 3 ];
d -> f;
f -> h [ minlen = 3 ];
f -> g;
}
[1]: excluded
")
Will look like:
Image with labels and empty nodes
grViz("
digraph cohort_flow_chart
{
node [fontname = Helvetica, fontsize = 12, shape = box, width = 4]
i[label = 'Identification', fillcolor = LightBlue,
style = filled, width = 2]
j[label = 'Screening',fillcolor = LightBlue, style = filled, width = 2]
k[label = 'Eligibility', fillcolor = LightBlue, style = filled,
width = 2]
l[label = 'Included', fillcolor = LightBlue, style = filled, width = 2]
a[label = 'Records identified in original search']
b[label = 'Records identified with update']
c[label = 'Records after duplicates removed']
d[label = 'Records screened']
e[label = 'Records excluded']
f[label = 'Full text articles assessed']
g[label = 'Studies included']
h[label = '##1']
blank_1[label = '', width = 0.01, height = 0.01]
blank_2[label = '', width = 0.01, height = 0.01]
blank_4[label = '', width = 4, color = White]
{ rank = same; a b i}
{ rank = same; blank_4 c j}
{ rank = same; f k}
{ rank = same; g l}
{ rank = same; blank_1 e}
{ rank = same; blank_2 h}
a -> c;
b -> c;
b -> blank_4 [ dir = none, color = White];
c -> d;
d -> blank_1 [ dir = none ];
blank_1 -> e [ minlen = 3 ];
blank_1 -> f;
f -> blank_2 [ dir = none ];
blank_2 -> h [ minlen = 3 ];
blank_2 -> g;
}
[1]: excluded
")
I'm using TwoAxisPlot to combine two plots for functions from an NDSolve, but the result has one of the curves truncated and is hence incomplete. I don't understand all the jargon when defining the TwoAxisPlot function so I don't know the origin of the problem. Code is as follows:
a = 0.99*10^-9;
b = 0.24*10^-3;
d = 1.21*10^-3;
T0 = 1*10^6;
n0 = 0.9*10^9;
ti = -20;
tf = 500;
kB = 1.38*10^-16;
Qb = 0.33*10^-3;
sig = 1;
var = sig^2;
Ag = 16.5;
Qg = Ag* Exp[-(t - 10)^2/(2*var)];
Qgt = Qg + Qb;
sss = NDSolve[{T'[t] == -(n[t]^-1) T[t]^(7/2) (a) -
n[t] T[t]^(-1/2) (b) + Qgt/(2*kB*n[t]),
n'[t] == T[t]^(5/2) (a) - (n[t]^2) (T[t]^(-3/2)) (d), T[ti] == T0,
n[ti] == n0}, {T, n}, {t, ti, tf}];
This gives me two interpolating functions which I can plot fully individually:
TP = Plot[T[t] /. sss, {t, ti, 300}, PlotRange -> All];
TPPa = Show[TP, Frame -> True,
FrameLabel -> {{"Temperature, K", ""}, {"Time, s", ""}}]
NP = Plot[n[t] /. sss, {t, ti, 300}, PlotRange -> All];
NPPa = Show[NP, Frame -> True,
FrameLabel -> {{"Density, \!\(\*SuperscriptBox[\(cm\), \(-3\)]\)",
""}, {"Time, s", ""}}]
I then define the TwoAxisPlot function, unchanged, copied from this website: Wolfram Documentation Center
TwoAxisPlot[{f_, g_}, {x_, x1_, x2_}] :=
Module[{fgraph, ggraph, frange, grange, fticks,
gticks}, {fgraph, ggraph} =
MapIndexed[
Plot[#, {x, x1, x2}, Axes -> True,
PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}]; {frange,
grange} = (PlotRange /. AbsoluteOptions[#, PlotRange])[[
2]] & /# {fgraph, ggraph}; fticks = N#FindDivisions[frange, 5];
gticks =
Quiet#Transpose#{fticks,
ToString[NumberForm[#, 2], StandardForm] & /#
Rescale[fticks, frange, grange]};
Show[fgraph,
ggraph /.
Graphics[graph_, s___] :>
Graphics[
GeometricTransformation[graph,
RescalingTransform[{{0, 1}, grange}, {{0, 1}, frange}]], s],
Axes -> False, Frame -> True,
FrameStyle -> {ColorData[1] /# {1, 2}, {Automatic, Automatic}},
FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}]]
and use it
TwoAxisPlot[{T[t] /. sss, n[t] /. sss}, {t, -20, 300}]
but the plot is now truncated and doesn't show the full curve. How can I fix this?
Add PlotRange -> Full as included below.
TwoAxisPlot[{f_, g_}, {x_, x1_, x2_}] := Module[
{fgraph, ggraph, frange, grange, fticks, gticks},
{fgraph, ggraph} = MapIndexed[Plot[#, {x, x1, x2}, Axes -> True,
PlotStyle -> ColorData[1][#2[[1]]], PlotRange -> Full] &, {f, g}];
{frange, grange} = (PlotRange /. AbsoluteOptions[#, PlotRange])[[2]] & /#
{fgraph, ggraph};
fticks = N#FindDivisions[frange, 5];
gticks = Quiet#Transpose#{fticks, ToString[NumberForm[#, 2],
StandardForm] & /# Rescale[fticks, frange, grange]};
Show[fgraph, ggraph /. Graphics[graph_, s___] :> Graphics[
GeometricTransformation[graph, RescalingTransform[{{0, 1}, grange},
{{0, 1}, frange}]], s], Axes -> False, Frame -> True,
FrameStyle -> {ColorData[1] /# {1, 2}, {Automatic, Automatic}},
FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}]]
Labeled[
TwoAxisPlot[{T[t] /. sss, n[t] /. sss}, {t, -20, 300}],
{Rotate["Temperature, K", Pi/2], "Time, s",
Rotate["Density, \!\(\*SuperscriptBox[\(cm\), \(-3\)]\)", Pi/2]},
{Left, Bottom, Right}]
I have the following code which works just fine.
I'm just wondering if there's a more elegant/optimized way of doing so.
Long "code" short, given the data:
var myArray = [
['X', 'A', 0, 1, 'Y', 3],
['X', 'A', 4, 5, 'Y', 6],
['X', 'B', 6, 5, 'Y', 4],
['X', 'B', 3, 2, 'Y', 1],
['X', 'C', 7, 8, 'Y', 9],
];
Say I want to group by column index 1 and only sum column indexes 2, 3, 5.
Expected result is:
[
["A", 4, 6, 9],
["B", 9, 7, 5],
["C", 7, 8, 9]
]
// data
var myArray = [
['X', 'A', 0, 1, 'Y', 3],
['X', 'A', 4, 5, 'Y', 6],
['X', 'B', 6, 5, 'Y', 4],
['X', 'B', 3, 2, 'Y', 1],
['X', 'C', 7, 8, 'Y', 9],
];
// col that I want to group by
var colIndex = 1;
// cols I want to sum
var colsToSum = [2, 3, 5];
var arrayGroupBy = function(myArray, colIndex, colsToSum) {
// get unique column values
var uniqueValues = [];
myArray.forEach(function(row) {
if (uniqueValues.indexOf(row[colIndex]) === -1) {
uniqueValues.push(row[colIndex]);
}
});
var newData = [];
uniqueValues.forEach(function(value) {
// get filtered rows
var filteredRows = myArray.filter(function(row) {
return row[colIndex] === value;
});
var row = [value];
// columns to sum
colsToSum.forEach(function(num) {
if (filteredRows.length === 1) {
// push single row
row.push(filteredRows[0][num]);
} else {
// sum row cols
var total = filteredRows.reduce(function(sum, current) {
return sum + current[num];
}, 0);
row.push(total);
}
});
newData.push(row);
});
return newData;
};
console.log(arrayGroupBy(myArray, colIndex, colsToSum));
Unfortunately I can't use ES6 on this one...
Thanks!
I tried to find a solution for your question. There would be many good ES6 features which would make the solution a bit more readable/cleaner. But here is a solution without any ES6 features:
var groupBy = function(myArray, colIndex, colsToSum) {
var obj = {};
myArray.forEach(function(e) {
if(!obj.hasOwnProperty(e)) {
obj[e[colIndex]] = new Array(colsToSum.length + 1)
.join('0').split('').map(parseFloat);
}
});
myArray.forEach(function(row) {
for (var i = 0; i < colsToSum.length; i++) {
obj[row[colIndex]][i] += row[colsToSum[i]];
}
});
return Object.keys(obj).map(function(key) {
return [key].concat(obj[key]);
});
}
Explanation:
An object with the properties 'A', 'B' and 'C' will be created.
An array [0, 0, 0] will be assigned to each property.
Loop myArray and colsToSum and add the values to the right object property
Convert the object to an array and return it
Maybe there are better solutions :)
Is anyone aware of an existing grammar definition of Mscgen syntax that will work with PegKit? I had a look in the "res" folder but most of those don't seem to work.
Here is a sample
# MSC for some fictional process
msc {
hscale = "2";
a,b,c;
a->b [ label = "ab()" ] ;
b->c [ label = "bc(TRUE)"];
c=>c [ label = "process(1)" ];
c=>c [ label = "process(2)" ];
...;
c=>c [ label = "process(n)" ];
c=>c [ label = "process(END)" ];
a<<=c [ label = "callback()"];
--- [ label = "If more to run", ID="*" ];
a->a [ label = "next()"];
a->c [ label = "ac1()\nac2()"];
b<-c [ label = "cb(TRUE)"];
b->b [ label = "stalled(...)"];
a<-b [ label = "ab() = FALSE"];
}