Related
This question already has an answer here:
Pretty print struct in Rust
(1 answer)
Closed 2 months ago.
format!("{:#?}", (100, 200)); // => "(
// 100,
// 200,
// )"
Any docs to elaborate on this pattern {:#?}?
? means a debug format (use Debug and not Display), # means pretty-printing the debug format. For example:
#[derive(Debug)]
struct S {
a: i32,
b: i32,
}
fn main() {
let v = S { a: 1, b: 2 };
println!("{v:?}");
println!("{v:#?}");
}
Prints (Playground):
S { a: 1, b: 2 }
S {
a: 1,
b: 2,
}
See the docs.
I have the following array of constants in Rust:
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
And the point is that I want to iterate over it like this:
for (i, count) in COUNTS.iter().enumerate() {
const length: usize = *count/2;
let indices: [usize; length] = Vec::from_iter(0..length).try_into().unwrap();
let set: IndexSet<usize> = IndexSet::from(indices);
...
}
The point is that from method of IndexSet requires a statically sized array, i.e., [T; N]. What's the proper way here to create a statically sized array that includes the half of the values? Because the above code throws an error at const length: usize = *count/2 that count is a non-constant.
You probably want to use .collect instead, which is a standard way to instantiate a collection (here IndexSet) from an other collection (here a range of numbers).
use indexmap::set::IndexSet;
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
fn main() {
for (i, count) in COUNTS.iter().copied().enumerate() {
let length = count/2;
let set = (0..length).collect::<IndexSet<_>>();
}
}
See the playground.
You need to statically add the array size:
let indices: [usize; 5] = Vec::from_iter(0..length).try_into().unwrap();
Which invalidates the purpouse of your code. That said, IndexSet implements FromIterator:
use indexmap::IndexSet;
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
fn main() {
for (i, count) in COUNTS.iter().enumerate() {
let length: usize = *count / 2;
let set: IndexSet<usize> = IndexSet::from_iter(0..length);
}
}
Playground
code first:
use std::collections::HashMap;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {
vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
m
}),*
]
};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
I have above macro to generate a vec, contains several HashMap, in which these HashMap value is a vec as well,
{"A": [1, 2, 3]} => vec value length: 3,
{"B": [3, 4]} => vec value length: 2,
I wanna all the HashMap have the same length,
how to write in the macro to control this?
You can change the macro so that it creates a block (second set of {} encapsulating the macro definition) that you can set helper variables in and do a second pass over your vector, resizing anything that is smaller than the largest array.
In this case I've resized the arrays with the default value of the type to keep it simple. You may wish to wrap the data in Some().
This:
use std::cmp;
use std::collections::HashMap;
use std::default::Default;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {{
let mut max = 0;
let mut result = vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
// Simply unwrap here as we know we inserted at this key above
max = cmp::max(max, m.get($t).unwrap().len());
m
}),*
];
for m in result.iter_mut() {
for v in m.values_mut() {
if v.len() < max {
v.resize_with(max, Default::default);
}
}
}
result
}};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
Yields:
[{"A": [1, 2, 3]}, {"B": [3, 4, 0]}]
In trying to chain std::iter::Iterator::take_while calls together I'm losing the last values of each call.
Is there a way to chain calls together like this without skipping values?
Code Playground link:
use std::fmt;
#[derive(Clone)]
struct Point {
value: u8,
xe: u8,
xs: u8,
y: u8,
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
fn main() {
// All values following 5s within its x distance, partitioned by whether it is above or below.
// Sorted by xs (x start) (xe = x end)
#[rustfmt::skip]
let vec:Vec<Point> = vec![
Point { value: 4, xe: 1, xs: 1, y: 2 }, // 4
Point { value: 3, xe: 3, xs: 2, y: 3 }, // 3
Point { value: 5, xe: 7, xs: 4, y: 6 }, // ---- 5 -----
Point { value: 3, xe: 5, xs: 5, y: 4 }, // 3
Point { value: 6, xe: 6, xs: 6, y: 8 }, // 6
Point { value: 2, xe: 8, xs: 8, y: 3 }, // 2
Point { value: 8, xe: 10, xs: 9, y: 2 }, // 8
Point { value: 5, xe: 15, xs: 10, y: 7 }, // ---- 5 -----
Point { value: 2, xe: 12, xs: 11, y: 10 }, // 2
Point { value: 7, xe: 13, xs: 13, y: 9 }, // 7
Point { value: 4, xe: 14, xs: 14, y: 2 } // 4
];
let mut iter = vec.iter();
loop {
let c: Vec<_> = iter
.by_ref()
.take_while(|x| x.value != 5)
.cloned()
.collect();
println!("c: {:.?}", c);
if let Some(var) = iter.next() {
println!("var: {:.?}", var);
let (a, b): (Vec<_>, Vec<_>) = iter
.by_ref()
.take_while(|x| x.xe < var.xe)
.partition(|x| x.y > var.y);
println!("a: {:.?}", a);
println!("b: {:.?}", b);
} else {
break;
}
}
}
Output:
c: [4, 3]
var: 3
a: []
b: []
c: [2, 8]
var: 2
a: []
b: []
c: [4]
It should output:
c: [4, 3]
var: 5
a: [3]
b: [6]
c: [2, 8]
var: 5
a: [2, 7]
b: [4]
Using take_while with std::iter::Iterator::partition seemed a good way to make the code for this relatively clean.
In context the c, a and b values would be passed to functions whose results would be appended to a return value.
Using next_if() and from_fn():
use std::iter::from_fn;
// ...
let mut iter = vec.iter().peekable();
// ...
let c: Vec<_> = from_fn(|| iter.next_if(|x| x.value != 5))
.cloned()
.collect();
// ...
let (a, b): (Vec<_>, Vec<_>) = from_fn(|| iter.next_if(|x| x.xe < var.xe))
.partition(|x| x.y > var.y);
Using peeking_take_while() (better) or take_while_ref() from itertools, just replace the function.
I am attempting to turn a flat structure like the following:
let flat = vec![
Foo {
a: "abc1".to_owned(),
b: "efg1".to_owned(),
c: "yyyy".to_owned(),
d: "aaaa".to_owned(),
},
Foo {
a: "abc1".to_owned(),
b: "efg2".to_owned(),
c: "zzzz".to_owned(),
d: "bbbb".to_owned(),
}];
into a nested JSON object through serde_json that looks something like:
{
"abc1": {
"efg1": {
"c": "hij1",
"d": "aaaa",
},
"efg2": {
"c": "zzzz",
"d": "bbbb",
},
}
}
(The values b are guaranteed to be unique within the array)
If I had needed only one layer, I would do something like this:
let map = flat.into_iter().map(|input| (input.a, NewType {
b: input.b,
c: input.c,
d: input.d,
})).collect::<Hashmap<String, NewType>>();
let out = serde_json::to_string(map).unwrap();
However, this doesn't seem to scale to multiple layers (i.e. (String, (String, NewType)) can't collect into Hashmap<String, Hashmap<String, NewType>>)
Is there a better way than manually looping and inserting entries into the hashmaps, before turning them into json?
A map will preserve the shape of the data. That is not what you want; the cardinality of the data has been changed after the transformation. So a mere map won't be sufficient.
Instead, a fold will do: you start with an empty HashMap, and populate it as you iterate through the collection. But it is hardly any more readable than a loop in this case. I find a multimap is quite useful here:
use multimap::MultiMap;
use std::collections::HashMap;
struct Foo {
a: String,
b: String,
c: String,
d: String,
}
#[derive(Debug)]
struct NewFoo {
c: String,
d: String,
}
fn main() {
let flat = vec![
Foo {
a: "abc1".to_owned(),
b: "efg1".to_owned(),
c: "yyyy".to_owned(),
d: "aaaa".to_owned(),
},
Foo {
a: "abc1".to_owned(),
b: "efg2".to_owned(),
c: "zzzz".to_owned(),
d: "bbbb".to_owned(),
},
];
let map = flat
.into_iter()
.map(|e| (e.a, (e.b, NewFoo { c: e.c, d: e.d })))
.collect::<MultiMap<_, _>>()
.into_iter()
.map(|e| (e.0, e.1.into_iter().collect::<HashMap<_, _>>()))
.collect::<HashMap<_, _>>();
println!("{:#?}", map);
}
If you need to do something custom to flatten/merge your Foo structure, you could turn it into json Values in your rust code using something this:
let mut root: Map<String, Value> = Map::new();
for foo in flat.into_iter() {
let b = json!({ "c": foo.c, "d": foo.d });
if let Some(a) = root.get_mut(&foo.a) {
if let Value::Object(map) = a {
map.insert(foo.b, b);
}
} else {
root.insert(foo.a, json!({foo.b: b}));
}
};
link to playground