How to convert BTreeSet to BTreeMap? - rust

I have a BTreeSet object and I want to convert it into a BTreeMap with default indices (i.e., starting from 0 and incrementing). More precisely, given this:
let set = BTreeSet::from([0, 2, 4, 6, 8]);
I want to end up with BTreeMap<usize, usize> that holds [(0, 0), (1, 2), (2, 4), (3, 6), (4, 8)]. I can do it with a loop for example as
let mut tree = BTreeMap::new();
for (i, v) in set.clone().into_iter().enumerate() {
tree.insert(i, v);
}
But is there any shortcut (i.e., one line code) that does the same?

But is there any shortcut (i.e., one line code) that does the same?
let map = set.iter().copied().enumerate().collect::<BTreeMap<_, _>>();
println!("{:?}", map);
{0: 0, 1: 2, 2: 4, 3: 6, 4: 8}
tho note that this is a BTreeMap<usize, i32>, because i32 is the default resolution for {integer} literals if they're otherwise unconstrained, which is the case here.

Related

Single cyclic iteration from middle of rust vector

I have a vector of some elements that I would like to iterate from some index and cycle around from the front again while only visiting each element a single time.
Ex. starting here at index 2,
[0, 1, 2, 3, 4, 5, 6]
^
I would like to have an iterator over the elements [2, 3, 4, 5, 6, 0, 1] (and avoid writing a loop everywhere I need to run through the vector this way).
The standard iteration with cycle() + skip() seemed to be a good start, but it of cause never ends.
Is there any idiomatic way with rusts standard iterators?
You can iterate over the two subslices, and use chain to concatenate them together into a single iterator:
let v = vec![0, 1, 2, 3, 4, 5, 6];
let start_index = 2;
for e in v[start_index..].iter().chain(v[..start_index].iter()) {
println!("{}", e);
}
The obvious fix for your cycle/skip combo is to add a take() to limit it:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().skip(start_pos).take(slice.len())
}
Another option is to just chain the two ranges, which even ends up a bit shorter:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice[start_pos..].iter().chain(&slice[..start_pos])
}
Both versions pass test such as:
let v = vec![0, 1, 2, 3, 4, 5, 6];
assert_eq!(cycle(&v, 2).copied().collect::<Vec<_>>(), vec![2, 3, 4, 5, 6, 0, 1]);

Rust iterator something like chunks()

This iterator
let data = vec![0, 1, 2, 3, 4, 5];
for x in data.chunks(2) {
println!("{:?}", x);
}
will produce
[0, 1]
[2, 3]
[4, 5]
Can I use iterator to get something like this.
[0, 1]
[1, 2]
[2, 3]
[3, 4]
[4, 5]
I know how to do that using for loop. But can iterator do this better?
I guess your can use Itertools.tuple_windows for this. According to the documentation it "returns an iterator over all contiguous windows producing tuples of a specific size (up to 4)" :
use itertools::Itertools;
use itertools::TupleWindows;
use std::slice::Iter;
let data = vec![0, 1, 2, 3, 4, 5];
let it: TupleWindows<Iter<'_, i32>, (&i32, &i32)> = data.iter().tuple_windows();
for elem in it {
println!("{:?}", elem);
}
Output:
(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
Edit:
As noted in comment1 by #Masklinn and comment2 by #SebastianRedl, you can also use windows from stdlib and avoid including Itertools in your project. But note that it only works for slices (or things that coerce to slices), not general iterators (which is fine in your case).
let data = vec![0, 1, 2, 3, 4, 5];
let it = data.windows(2);
for elem in it {
println!("{:?}", elem);
}
Output:
[0, 1]
[1, 2]
[2, 3]
[3, 4]
[4, 5]
Alternatively, without extra dependencies, you can zip the same iterator, skip one item on the second one.
fn main() {
let data = vec![0, 1, 2, 3, 4, 5];
let i1 = data.iter();
let i2 = data.iter();
for (a, b) in i1.zip(i2.skip(1)) {
println!("{} {}", a, b);
}
}
Playground

Sort a hashmap by values in rust

In python its done this way:
>>> x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> {k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}
How to sort a HashMap by values in rust?
My code so far:
use std::collections::HashMap;
fn main() {
let mut count: HashMap<String, u32>= HashMap::new();
count.insert(String::from("A"), 5);
count.insert(String::from("B"), 2);
count.insert(String::from("C"), 11);
count.insert(String::from("D"), 10);
let highest = count.iter().max_by(|a, b| a.1.cmp(&b.1)).unwrap();
println!("largest hash: {:?}", highest); // largest hash: ("C", 11)
}
Unlike Python's dict, Rust's "built-in" hashmap is not ordered, so sorting it has no effect.
If you need an ordered map for some reason, you should use indexmap. Alternatively, BTreeMap is sorted based on the key.
As you don't really present any sort of compelling use case it's hard to provide counsel though.
Ya, sorted it by converting to vector:
use std::collections::HashMap;
fn main() {
let mut count: HashMap<String, u32>= HashMap::new();
count.insert(String::from("A"), 5);
count.insert(String::from("B"), 2);
count.insert(String::from("C"), 11);
count.insert(String::from("D"), 10);
let mut hash_vec: Vec<(&String, &u32)> = count.iter().collect();
println!("{:?}", hash_vec);
hash_vec.sort_by(|a, b| b.1.cmp(a.1));
println!("Sorted: {:?}", hash_vec); //Sorted: [("C", 11), ("D", 10), ("A", 5), ("B", 2)]
}
Sort HashMap data by value

How to concatenate the individual elements of a vector of slices with other slices?

I have a slice of bytes start = [30u8; 5] and middle = [40u8; 3] and a vector of byte slices:
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
I want to concatenate everything together, in such a way that I will obtain a single byte slice which looks as
[30, 30, 30, 30, 30, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
However, although I can concatenate start and middle when I try to append the vector elements it fails. I know that I am wrongly trying to iterate through the elements of the vector to concatenate, but I can't figure out how to do it correctly?
fn main() {
let start = [30u8; 5];
let middle = [40u8; 4];
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
println!("{:?}", elements.iter());
for key in elements.iter() {
println!("{:?}", key.iter());
}
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().iter().cloned())
.collect();
println!("{:?}", alltogether);
}
This example can be copy-pasted into the Rust playground.
You possibly want this:
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().flatten().cloned())
.collect();
Note that there is also copied (instead of cloned) that can be used for Copyable types.
If the stuff in elements does not implement IntoIterator itself, you can use flat_map to specify how to convert one element to an iterator.

Get indexes of all occurrences of a substring within a string

If I wanted to get the index of the first occurrence of, say, substring "foo" within a string "foo bar foo baz foo", I'd use:
fn main() {
let my_string = String::from("foo bar foo baz foo");
println!("{:?}", my_string.find("foo"));
}
...which would give me Some(0).
However, I need to find indexes of all occurrences of a substring within a string.
In this scenario, I'd need something like:
[0, 8, 16]
How can I do this idiomatically in Rust?
Use match_indices. Example from Rust docs:
let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
assert_eq!(v, [(1, "abc"), (4, "abc")]);
let v: Vec<_> = "ababa".match_indices("aba").collect();
assert_eq!(v, [(0, "aba")]); // only the first `aba`
I think the most complete answer, based on the OP's requirement, would be:
let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").map(|(i, _)|i).collect();
assert_eq!(v, [0,6,12]);
There is a match_indices: https://doc.rust-lang.org/std/string/struct.String.html#method.match_indices
let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);

Resources