Repeat string with integer multiplication - rust

Is there an easy way to do the following (from Python) in Rust?
>>> print ("Repeat" * 4)
RepeatRepeatRepeatRepeat
I'm starting to learn the language, and it seems String doesn't override Mul, and I can't find any discussion anywhere on a compact way of doing this (other than a map or loop).

Rust 1.16+
str::repeat is now available:
fn main() {
let repeated = "Repeat".repeat(4);
println!("{}", repeated);
}
Rust 1.0+
You can use iter::repeat:
use std::iter;
fn main() {
let repeated: String = iter::repeat("Repeat").take(4).collect();
println!("{}", repeated);
}
This also has the benefit of being more generic — it creates an infinitely repeating iterator of any type that is cloneable.

This one doesn't use Iterator::map but Iterator::fold instead:
fn main() {
println!("{:?}", (1..5).fold(String::new(), |b, _| b + "Repeat"));
}

Related

How can I join a Vec<> of i32 numbers into a String? [duplicate]

This question already has answers here:
What's an idiomatic way to print an iterator separated by spaces in Rust?
(4 answers)
Closed 2 years ago.
I want to join a list of numbers into a String. I have the following code:
let ids: Vec<i32> = Vec::new();
ids.push(1);
ids.push(2);
ids.push(3);
ids.push(4);
let joined = ids.join(",");
print!("{}", joined);
However, I get the following compilation error:
error[E0599]: no method named `join` found for struct `std::vec::Vec<i32>` in the current scope
--> src\data\words.rs:95:22
|
95 | let joined = ids.join(",");
| ^^^^ method not found in `std::vec::Vec<i32>`
|
= note: the method `join` exists but the following trait bounds were not satisfied:
`<[i32] as std::slice::Join<_>>::Output = _`
I'm a bit unclear as to what to do. I understand the implementation of traits, but whatever trait it's expecting, I would expect to be natively implemented for i32. I would expect joining integers into a string to be more trivial than this. Should I cast all of them to Strings first?
EDIT: It's not the same as the linked question, because here I am specifically asking about numbers not being directly "joinable", and the reason for the trait to not be implemented by the number type. I looked fairly hard for something in this direction and found nothing, which is why I asked this question.
Also, it's more likely that someone will search specifically for a question phrased like this instead of the more general "idiomatic printing of iterator values".
I would do
let ids = vec!(1,2,3,4);
let joined: String = ids.iter().map( |&id| id.to_string() + ",").collect();
print!("{}", joined);
Generally when you have a collection of one type in Rust, and want to turn it to another type, you call .iter().map(...) on it. The advantage of this method is you keep your ids as integers which is nice, have no mutable state, and don't need an extra library. Also if you want a more complex transformation than just a casting, this is a very good method. The disadvantage is you have a trailing comma in joined. playground link
If you don't want to explicitly convert into string, then you can use Itertools::join method (this is an external crate though)
PlayGround
Relevant code:
use itertools::Itertools;
let mut ids: Vec<i32> = ...;
let joined = Itertools::join(&mut ids.iter(), ",");
print!("{}", joined);
Frxstrem suggestion:
let joined = ids.iter().join(".");
Using the [T]::join() method requires that [T] implements the Join trait. The Join trait is only implemented for [T] where T implements Borrow<str> (like String or &str) or Borrow<[U]> (like &[U] or Vec<U>). In other words, you can only join a vector of strings or a vector of slices/vectors.
In general, Rust requires you to be very explicit about type conversion, so in many cases you shouldn't expect the language to e.g. automatically convert an integer to a string for you.
To solve your problem, you need to explicitly convert your integers into strings before pushing them into your vector:
let mut ids: Vec<String> = Vec::new();
ids.push(1.to_string());
ids.push(2.to_string());
ids.push(3.to_string());
ids.push(4.to_string());
let joined = ids.join(",");
print!("{}", joined);
Playground example
If you want a generic solution:
fn join<I, T>(it: I, sep: &str) -> String
where
I: IntoIterator<Item = T>,
T: std::fmt::Display,
{
use std::fmt::Write;
let mut it = it.into_iter();
let first = it.next().map(|f| f.to_string()).unwrap_or_default();
it.fold(first, |mut acc, s| {
write!(acc, "{}{}", sep, s).expect("Writing in a String shouldn't fail");
acc
})
}
fn main() {
assert_eq!(join(Vec::<i32>::new(), ", "), "");
assert_eq!(join(vec![1], ", "), "1");
assert_eq!(join(vec![1, 2, 3, 4], ", "), "1, 2, 3, 4");
}
Maybe this implement
If you prefer that style, you can use an extension method:
trait JoinIterator {
fn join(self, sep: &str) -> String;
}
impl<I, T> JoinIterator for I
where
I: IntoIterator<Item = T>,
T: std::fmt::Display,
{
fn join(self, sep: &str) -> String {
use std::fmt::Write;
let mut it = self.into_iter();
let first = it.next().map(|f| f.to_string()).unwrap_or_default();
it.fold(first, |mut acc, s| {
write!(acc, "{}{}", sep, s).expect("Writing in a String shouldn't fail");
acc
})
}
}
fn main() {
assert_eq!(Vec::<i32>::new().join(", "), "");
assert_eq!(vec![1].join(", "), "1");
assert_eq!(vec![1, 2, 3, 4].join(", "), "1, 2, 3, 4");
}

Join iterator of &str [duplicate]

This question already has answers here:
What's an idiomatic way to print an iterator separated by spaces in Rust?
(4 answers)
Closed 3 years ago.
How do I convert an Iterator<&str> to a String, interspersed with a constant string such as "\n"?
For instance, given:
let xs = vec!["first", "second", "third"];
let it = xs.iter();
One may produce a string s by collecting into a Vec<&str> and joining the result:
let s = it
.map(|&x| x)
.collect::<Vec<&str>>()
.join("\n");
However, this unnecessarily allocates memory for a Vec<&str>.
Is there a more direct method?
You could use the itertools crate for that. I use the intersperse helper in the example, it is pretty much the join equivalent for iterators.
cloned() is needed to convert &&str items to &str items, it is not doing any allocations. It can be eventually replaced by copied() when rust#1.36 gets a stable release.
use itertools::Itertools; // 0.8.0
fn main() {
let words = ["alpha", "beta", "gamma"];
let merged: String = words.iter().cloned().intersperse(", ").collect();
assert_eq!(merged, "alpha, beta, gamma");
}
Playground
You can do it by using fold function of the iterator easily:
let s = it.fold(String::new(), |a, b| a + b + "\n");
The Full Code will be like following:
fn main() {
let xs = vec!["first", "second", "third"];
let it = xs.into_iter();
// let s = it.collect::<Vec<&str>>().join("\n");
let s = it.fold(String::new(), |a, b| a + b + "\n");
let s = s.trim_end();
println!("{:?}", s);
}
Playground
EDIT: After the comment of Sebastian Redl I have checked the performance cost of the fold usage and created a benchmark test on playground.
You can see that fold usage takes significantly more time for the many iterative approaches.
Did not check the allocated memory usage though.
there's relevant example in rust documentation: here.
let words = ["alpha", "beta", "gamma"];
// chars() returns an iterator
let merged: String = words.iter()
.flat_map(|s| s.chars())
.collect();
assert_eq!(merged, "alphabetagamma");
You can also use Extend trait:
fn f<'a, I: Iterator<Item=&'a str>>(data: I) -> String {
let mut ret = String::new();
ret.extend(data);
ret
}

Searching for a matching subslice? [duplicate]

I have a &[u8] slice over a binary buffer. I need to parse it, but a lot of the methods that I would like to use (such as str::find) don't seem to be available on slices.
I've seen that I can covert both by buffer slice and my pattern to str by using from_utf8_unchecked() but that seems a little dangerous (and also really hacky).
How can I find a subsequence in this slice? I actually need the index of the pattern, not just a slice view of the parts, so I don't think split will work.
Here's a simple implementation based on the windows iterator.
fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
haystack.windows(needle.len()).position(|window| window == needle)
}
fn main() {
assert_eq!(find_subsequence(b"qwertyuiop", b"tyu"), Some(4));
assert_eq!(find_subsequence(b"qwertyuiop", b"asd"), None);
}
The find_subsequence function can also be made generic:
fn find_subsequence<T>(haystack: &[T], needle: &[T]) -> Option<usize>
where for<'a> &'a [T]: PartialEq
{
haystack.windows(needle.len()).position(|window| window == needle)
}
I don't think the standard library contains a function for this. Some libcs have memmem, but at the moment the libc crate does not wrap this. You can use the twoway crate however. rust-bio implements some pattern matching algorithms, too. All of those should be faster than using haystack.windows(..).position(..)
I found the memmem crate useful for this task:
use memmem::{Searcher, TwoWaySearcher};
let search = TwoWaySearcher::new("dog".as_bytes());
assert_eq!(
search.search_in("The quick brown fox jumped over the lazy dog.".as_bytes()),
Some(41)
);
How about Regex on bytes? That looks very powerful. See this Rust playground demo.
extern crate regex;
use regex::bytes::Regex;
fn main() {
//see https://doc.rust-lang.org/regex/regex/bytes/
let re = Regex::new(r"say [^,]*").unwrap();
let text = b"say foo, say bar, say baz";
// Extract all of the strings without the null terminator from each match.
// The unwrap is OK here since a match requires the `cstr` capture to match.
let cstrs: Vec<usize> =
re.captures_iter(text)
.map(|c| c.get(0).unwrap().start())
.collect();
assert_eq!(cstrs, vec![0, 9, 18]);
}

How to build an Rc<str> or Rc<[T]>?

I'd like to create an Rc<str> because I want reduce the indirection from following the 2 pointers that accessing an Rc<String> requires. I need to use an Rc because I truly have shared ownership. I detail in another question more specific issues I have around my string type.
Rc has a ?Sized bound:
pub struct Rc<T: ?Sized> { /* fields omitted */ }
I've also heard that Rust 1.2 will come with proper support for storing unsized types in an Rc, but I'm unsure how this differs from 1.1.
Taking the str case as example, my naive attempt (also this for building from a String) fails with:
use std::rc::Rc;
fn main() {
let a: &str = "test";
let b: Rc<str> = Rc::new(*a);
println!("{}", b);
}
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> src/main.rs:5:22
|
5 | let b: Rc<str> = Rc::new(*a);
| ^^^^^^^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: required by `<std::rc::Rc<T>>::new`
It's clear that in order to create an Rc<str>, I need to copy the whole string: RcBox would be itself an unsized type, storing the string itself alongside the weak and strong pointers — the naive code above doesn't even make sense.
I've been told that one can not instantiate such type, but instead instantiate an Rc<T> with a sized T and then coerce it to an unsized type. The example given is for the storing a trait object: first create Rc<ConcreteType> and then coerce to Rc<Trait>. But this doesn't make sense either: neither this nor this work (and you can't coerce from &str or String to str anyway).
As of Rust 1.21.0 and as mandated by RFC 1845, creating an Rc<str> or Arc<str> is now possible:
use std::rc::Rc;
use std::sync::Arc;
fn main() {
let a: &str = "hello world";
let b: Rc<str> = Rc::from(a);
println!("{}", b);
// or equivalently:
let b: Rc<str> = a.into();
println!("{}", b);
// we can also do this for Arc,
let a: &str = "hello world";
let b: Arc<str> = Arc::from(a);
println!("{}", b);
}
(Playground)
See <Rc as From<&str>> and <Arc as From<&str>>.
Creating an Rc<[T]> can be done via coercions and as-casts from fixed sized arrays, e.g. coercions can be done as follows:
use std::rc::Rc;
fn main() {
let x: Rc<[i32; 4]> = Rc::new([1, 2, 3, 4]);
let y: Rc<[i32]> = x;
println!("{:?}", y);
}
However, this doesn't work for strings, since they have no raw fixed-sized equivalent to create the first value. It is possible to do unsafely, e.g. by creating a UTF-8 encoded Rc<[u8]> and transmuting that to Rc<str>. Theoretically there could be a crate on crates.io for it, but I can't find one at the moment.
An alternative is owning_ref, which isn't quite std::rc::Rc itself, but should allow, for example, getting an RcRef<..., str> pointing into an Rc<String>. (This approach will work best if one uses RcRef uniformly in place of Rc, except for construction.)
extern crate owning_ref;
use owning_ref::RcRef;
use std::rc::Rc;
fn main() {
let some_string = "foo".to_owned();
let val: RcRef<String> = RcRef::new(Rc::new(some_string));
let borrowed: RcRef<String, str> = val.map(|s| &**s);
let erased: RcRef<owning_ref::Erased, str> = borrowed.erase_owner();
}
The erasing means that RcRef<..., str>s can come from multiple different sources, e.g. a RcRef<Erased, str> can come from a string literal too.
NB. at the time of writing, the erasure with RcRef requires a nightly compiler, and depending on owning_ref with the nightly feature:
[dependencies]
owning_ref = { version = "0.1", features = ["nightly"] }

Reversing a string in Rust

What is wrong with this:
fn main() {
let word: &str = "lowks";
assert_eq!(word.chars().rev(), "skwol");
}
I get an error like this:
error[E0369]: binary operation `==` cannot be applied to type `std::iter::Rev<std::str::Chars<'_>>`
--> src/main.rs:4:5
|
4 | assert_eq!(word.chars().rev(), "skwol");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `std::iter::Rev<std::str::Chars<'_>>`
= note: this error originates in a macro outside of the current crate
What is the correct way to do this?
Since, as #DK. suggested, .graphemes() isn't available on &str in stable, you might as well just do what #huon suggested in the comments:
fn main() {
let foo = "palimpsest";
println!("{}", foo.chars().rev().collect::<String>());
}
The first, and most fundamental, problem is that this isn't how you reverse a Unicode string. You are reversing the order of the code points, where you want to reverse the order of graphemes. There may be other issues with this that I'm not aware of. Text is hard.
The second issue is pointed out by the compiler: you are trying to compare a string literal to a char iterator. chars and rev don't produce new strings, they produce lazy sequences, as with iterators in general. The following works:
/*!
Add the following to your `Cargo.toml`:
```cargo
[dependencies]
unicode-segmentation = "0.1.2"
```
*/
extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;
fn main() {
let word: &str = "loẅks";
let drow: String = word
// Split the string into an Iterator of &strs, where each element is an
// extended grapheme cluster.
.graphemes(true)
// Reverse the order of the grapheme iterator.
.rev()
// Collect all the chars into a new owned String.
.collect();
assert_eq!(drow, "skẅol");
// Print it out to be sure.
println!("drow = `{}`", drow);
}
Note that graphemes used to be in the standard library as an unstable method, so the above will break with sufficiently old versions of Rust. In that case, you need to use UnicodeSegmentation::graphemes(s, true) instead.
If you are just dealing with ASCII characters, you can make the reversal in place with the unstable reverse function for slices.
It is doing something like that:
fn main() {
let mut slice = *b"lowks";
let end = slice.len() - 1;
for i in 0..end / 2 {
slice.swap(i, end - i);
}
assert_eq!(std::str::from_utf8(&slice).unwrap(), "skwol");
}
Playground

Resources