How do I convert something like this:
let mut a = vec![1, 2, 3, 4i32];
for i in a.iter_mut() {
*i += 1;
}
to a one line operation using map and a closure?
I tried:
a.iter_mut().map(|i| *i + 1).collect::<Vec<i32>>();
The above only works if I reassign it to a. Why is this? Is map getting a copy of a instead of a mutable reference? If so, how can I get a mutable reference?
Your code dereferences the variable (*i) then adds one to it. Nowhere in there does the original value get changed.
The best way to do what you asked is to use Iterator::for_each:
a.iter_mut().for_each(|i| *i += 1);
This gets an iterator of mutable references to the numbers in your vector. For each item, it dereferences the reference and then increments it.
You could use map and collect, but doing so is non-idiomatic and potentially wasteful. This uses map for the side-effect of mutating the original value. The "return value" of assignment is the unit type () - an empty tuple. We use collect::<Vec<()>> to force the Iterator adapter to iterate. This last bit ::<...> is called the turbofish and allows us to provide a type parameter to the collect call, informing it what type to use, as nothing else would constrain the return type.:
let _ = a.iter_mut().map(|i| *i += 1).collect::<Vec<()>>();
You could also use something like Iterator::count, which is lighter than creating a Vec, but still ultimately unneeded:
a.iter_mut().map(|i| *i += 1).count();
As Ry- says, using a for loop is more idiomatic:
for i in &mut a {
*i += 1;
}
Related
Why I'm getting "java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0" while running next code??? :
val totalList = mutableListOf<MutableList<Int>>()
fun main() {
for (i in 0..15) {
for (j in 0..10) {
*some operations and calculations with **var element of type Int***
totalList[i].add(element)
}
}
}
I was thinking that in such case while iterating through 'j' it should add elements to mutableList[i], after this it should start adding elements to mutableList[i + 1] etc.... But instead I am recieving IndexOutOfBoundsException....
val totalList = mutableListOf<MutableList<Int>>()
All this does is create one list which is going to contain MutableList<Int> items. Right now, there's nothing in it (you've supplied no initial elements in the parentheses).
Skip forward a bit, and you do this:
totalList[0].add(element)
You're trying to get the first element of that empty list and add to it. But there is no first element (index 0) because the list is empty (length 0). That's what the error is telling you.
There's lots of ways to handle this - one thing you could do is create your lists up-front:
// create the 16 list items you want to access in the loop
// (the number is the item count, the lambda generates each item)
val totalList = MutableList(16) { mutableListOf<Int>() }
// then refer to that list's properties in your loop (no hardcoded 0..15)
for (i in totalList.indices) {
...
// guaranteed to exist since i is generated from the list's indices
totalList[i].add(element)
}
Or you could do it the way you are now, only using getOrElse to generate the empty list on-demand, when you try to get it but it doesn't exist:
for (i in 0..15) {
for (j in 0..10) {
// if the element at i doesn't exist, create a list instead, but also
// add it to the main list (see below)
totalList.getOrElse(i) {
mutableListOf<Int>().also { totalList.add(it) }
}.add(element)
}
}
Personally I don't really like this, you're using explicit indices but you're adding new list items to the end of the main list. That implicity requires that you're iterating over the list items in order - which you are here, but there's nothing enforcing that. If the order ever changed, it would break.
I'd prefer the first approach - create your structure of lists in advance, then iterate over those and fill them as necessary. Or you might want to consider arrays instead, since you have a fixed collection size you're "completing" by adding items to specific indices
Another approach (that I mentioned in the comments) is to create each list as a whole, complete thing, and then add that to your main list. This is generally how you do things in Kotlin - the standard library contains a lot of functional tools to allow you to chain operations together, transform things, and create immutable collections (which are safer and more explicit about whether they're meant to be changed or they're a fixed set of data).
for (i in 0..15) {
// map transforms each element of the range (each number) to an item,
// resulting in a list of items
val items = (0..10).map { j ->
// do whatever you're doing
// the last expression in the lambda is its resulting value,
// i.e. the item that ends up in the list
element
}
// now you have a complete list of items, add them to totalList
totalList.add(items)
}
(Or you could create the list directly with List(11) { j -> ... } but this is a more general example of transforming a bunch of things to a bunch of other things)
That example there is kinda half and half - you still have the imperative for loop going on as well. Writing it all using the same approach, you can get:
val totalList = (0..15).map { i ->
(0..10).map { j ->
// do stuff
element
}
}
I'd probably prefer the List(count) { i -> ... } approach for this, it's a better fit (this is a general example). That would also be better since you could use MutableList instead of List, if you really need them to be mutable (with the maps you could just chain .toMutableList() after the mapping function, as another step in the chain). Generally in Kotlin, collections are immutable by default, and this kind of approach is how you build them up without having to create a mutable list etc. and add items to it yourself
The following example of Kotlin source code returns an error when compiled:
fun main() {
var index: Int // create an integer used to call an index of an array
val myArray = Array(5) {i -> i + 1} // create an array to call from
val condition = true // makes an if statement run true later
if (condition) {
index = 2 // sets index to 2
}
println( myArray[index] ) // should print 2; errors
}
The error says that the example did not initialize the variable index by the time it is called, even though it is guaranteed to initialize within the if statement. I understand that this problem is easily solved by initializing index to anything before the if statement, but why does the compiler not initialize it? I also understand that Kotlin is still in beta; is this a bug, or is it intentional? Finally, I am using Replit as an online IDE; is there a chance that the compiler on the website simply is an outdated compiler?
The compiler checks whether there is a path in your code that the index may not be initialized based on all the path available in your code apart from the value of the parameters. You have an if statement without any else. If you add the else statement you will not get any compile error.
This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
Closed 2 years ago.
I'm currently learning Rust coming from JavaScript.
My problem is the following:
fn main() {
let name = String::from("Tom");
let sliced = name[..2];
println!("{}, {}", name, sliced);
}
This doesn't work. Saying "doesn't have a size known at compile-time".
To fix this I need to add & the referencing operator.
fn main() {
let name = String::from("Tom");
let sliced = &name[..2];
println!("{}, {}", name, sliced);
}
I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that?
By referencing a variable the reference refers to variable name but does not own it. The original value will not get dropped if my reference gets out of scope. Does that mean that the variable gets out of scope if i do name[...] and the variable gets dropped and because of that i need to create a reference to it to prevent that?
Could somebody explain me that?
I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that.
I understand where the confusion come from, because when you look at index() it returns &Self::Output. So it already returns a reference, what's going on?
It's because the indexing operator is syntactic sugar and uses the Index trait. However, while it uses index() which does return a reference, that is not how it is desugared.
In short x[i] is not translated into x.index(i), but actually to *x.index(i), so the reference is immediately dereferenced. That's how you end up with a str instead of a &str.
let foo = "foo bar"[..3]; // str
// same as
let foo = *"foo bar".index(..3); // str
That's why you need to add the & to get it "back" to a reference.
let foo = &"foo bar"[..3]; // &str
// same as
let foo = &*"foo bar".index(..3); // &str
Alternatively, if you call index() directly, then it isn't implicitly dereferenced of course.
use std::ops::Index;
let foo = "foo bar".index(..3); // &str
Trait std::ops::Index - Rust Documentation:
container[index] is actually syntactic sugar for *container.index(index)
The same applies to IndexMut.
It seems that an iterator is consumed when counting. How can I use the same iterator for counting and then iterate on it?
I'm trying to count the lines in a file and then print them. I am able to read the file content, I'm able to count the lines count, but then I'm no longer able to iterate over the lines as if the internal cursor was at the end of the iterator.
use std::fs::File;
use std::io::prelude::*;
fn main() {
let log_file_name = "/home/myuser/test.log";
let mut log_file = File::open(log_file_name).unwrap();
let mut log_content: String = String::from("");
//Reads the log file.
log_file.read_to_string(&mut log_content).unwrap();
//Gets all the lines in a Lines struct.
let mut lines = log_content.lines();
//Uses by_ref() in order to not take ownership
let count = lines.by_ref().count();
println!("{} lines", count); //Prints the count
//Doesn't enter in the loop
for value in lines {
println!("{}", value);
}
}
Iterator doesn't have a reset method, but it seems the internal cursor is at the end of the iterator after the count. Is it mandatory to create a new Lines by calling log_content.lines() again or can I reset the internal cursor?
For now, the workaround that I found is create a new iterator:
use std::fs::File;
use std::io::prelude::*;
fn main() {
let log_file_name = "/home/myuser/test.log";
let mut log_file = File::open(log_file_name).unwrap();
let mut log_content: String = String::from("");
//Reads the log file.
log_file.read_to_string(&mut log_content).unwrap();
//Counts all and consume the iterator
let count = log_content.lines().count();
println!("{} lines", count);
//Creates a pretty new iterator
let lines = log_content.lines();
for value in lines {
println!("{}", value);
}
}
Calling count consumes the iterator, because it actually iterates until it is done (i.e. next() returns None).
You can prevent consuming the iterator by using by_ref, but the iterator is still driven to its completion (by_ref actually just returns the mutable reference to the iterator, and Iterator is also implemented for the mutable reference: impl<'a, I> Iterator for &'a mut I).
This still can be useful if the iterator contains other state you want to reuse after it is done, but not in this case.
You could simply try forking the iterator (they often implement Clone if they don't have side effects), although in this case recreating it is just as good (most of the time creating an iterator is cheap; the real work is usually only done when you drive it by calling next directly or indirectly).
So no, (in this case) you can't reset it, and yes, you need to create a new one (or clone it before using it).
The other answers have already well-explained that you can either recreate your iterator or clone it.
If the act of iteration is overly expensive or it's impossible to do multiple times (such as reading from a network socket), an alternative solution is to create a collection of the iterator's values that will allow you to get the length and the values.
This does require storing every value from the iterator; there's no such thing as a free lunch!
use std::fs;
fn main() {
let log_content = fs::read_to_string("/home/myuser/test.log").unwrap();
let lines: Vec<_> = log_content.lines().collect();
println!("{} lines", lines.len());
for value in lines {
println!("{}", value);
}
}
Iterators can generally not be iterated twice because there might be a cost to their iteration. In the case of str::lines, each iteration needs to find the next end of line, which means scanning through the string, which has some cost. You could argue that the iterator could save those positions for later reuse, but the cost of storing them would be even bigger.
Some Iterators are even more expensive to iterate, so you really don't want to do it twice.
Many iterators can be recreated easily (here calling str::lines a second time) or be cloned. Whichever way you recreate an iterator, the two iterators are generally completely independent, so iterating will mean you'll pay the price twice.
In your specific case, it is probably fine to just iterate the string twice as strings that fit in memory shouldn't be so long that merely counting lines would be a very expensive operation. If you believe this is the case, first benchmark it, second, write your own algorithm as Lines::count is probably not optimized as much as it could since the primary goal of Lines is to iterate lines.
I have two objective c methods. One needs to return an int[][] and the other which needs to take int[][] as a parameter. I was originally using an NSMutableArray with NSMutableArrays as values however I was told to redo it like this in order to be compatible with some current code. I can't figure out how to make this work. I'm not sure I'm even googling the right thing. Anyway here is what I have now.
+(int [][consantValue]) getCoefficients
{
int coefficiennts [constantValue2][constantValue1] = { {0,1,2}, {3,4,5}, {6,7,8} };
return coefficients;
}
At the return statement I get the Error "Array initilizer must be an initializer list'
I also have to take the int[][] and rebuild it into an NSMutableArray of NSMutableArrays in another method but I'm hoping if someone can give me a hint on the first part I can work the second part out myself although if anyone has any advice on that I would appreciate it as well. Thanks.
The easy way to do this for fixed size array(s) is to use a struct for storage:
typedef struct {
int at[constantValue2][constantValue1];
} t_mon_coefficients;
And then you'd declare the method which returns by value:
+ (t_mon_coefficients)coefficients;
And passes by value as a parameter:
- (void)setCoefficients:(const t_mon_coefficients)pCoefficients;
If the struct is large, you should pass by reference:
// you'd use this like:
// t_mon_coefficients coef;
// [SomeClass getCoefficients:&coef];
+ (void)getCoefficients:(t_mon_coefficients* const)pOutCoefficients;
- (void)setCoefficients:(const t_mon_coefficients*)pCoefficients;
But there are multiple ways one could accomplish this.