I am trying to write a function that removes all occurrences of 1,2 and 3 from an array of unsigned integers. I have used the retain method but the error I am getting is:
rustc -o main main.rs
error[E0599]: no method named `retain` found for array `[u32; 7]` in the current scope
--> main.rs:3:5
|
3 | arr.retain(|&x| x != 1 || x != 2 || x != 3);
| ^^^^^^ method not found in `[u32; 7]`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
compiler exit status 1
This is what I have so far:
fn remover(arr:[u32;7]){
arr.retain(|&x| x != 1 || x != 2 || x != 3);
println!("{:?}",arr);
}
fn main() {
let v = [1,2,3,4,5,6,7];
remover(v);
}
Why can I not use the retain method? Is there something else I can use?
An array has a fixed size ([u32; 7] will always have 7 elements), therefore it doesn't make sense to remove elements from it.
If you want a dynamically sized sequence, you should use Vec, which does have a retain method.
Or you could keep an array and use Iterator::filter, if you don't actually need to update the source.
Arrays are statically sized in Rust, its size is part of the type. [u32; 7] defines the array to hold exactly 7 u32 values.
If you want to have a dynamic number of values, you will need to use Vec<u32> instead, i.e. declare v as vec![1,2,3,4,5,6,7] and make your remover() take Vec<u32> instead.
An alternative solution, you can proceed to filter to a slice of your array. By doing you do not duplicate data, avoiding creating a new vector.
fn main()
{
let v = [1,2,3,4,5,6,7];
let v_filtered = &v
.iter()
.filter(|&&x| x != 1 && x != 2 && x != 3)
.inspect(|&&x| println!("retained {}", x))
.collect::<Vec<_>>();
dbg!(v);
dbg!(v_filtered);
}
Pay attention, I changed the predicate of my filter.
Here is my playground
You can remove debugging info and iteration inspection value for the release version.
Related
I'm having some trouble around arrays in OCaml.
Namely, I want to just shift the elements to the right or left based on a value I pass.
Example: # let a = [|1;2;3;4;5|], # shift_array a 7;;- : int array array = [|4;5;1;2;3|]
I wrote the following code but I keep getting a syntax error where the second array is formed.
let shift_array arr x =
let size = Array.length arr in
let sec_arr = Array.make size 0 in
for i = 0 to size - 1 do
if i < x
then (sec_arr.(size - x + 1) <- arr.(i))
else (sec_arr.(i-x) <- arr.(i))
done;;
I'm just not 100% sure how to print out the new array.
EDIT: fixed it by adding in to the second and third line.
The problem now is that the function has type int array -> int -> unit and the one I'm trying to get is 'a array -> int -> 'a array. Is there some way to work around that ?
It should be let size = Array.length arr in, notice the in, which you're missing.
The let expression in OCaml has the form let <var> = <expr> in <body> and should not be (but commonly is) confused with the let definition that can occur only on the top-level (as an element of a module), which has form let <name> = <body>.
In your example, you have both, the top-level definition, let shift_array = <body> and two let expressions (though, you have used the wrong syntax for them.
EDIT:
Since OP edited the post, here is the corresponding edit.
You function doesn't return anything, it creates a new array, does the cycle, but doesn't return anything but the unit value (which is the value to which the for cycle evaluates). So you have to add one more line, that will contain the expression, to which the whole function will evaluate. Hint the sequencing operator ; is what you need, when you have expression x;y;z the computer evaluates x, then y, and finally z and the value of the whole expression of x;y;z is the value of z.
Consider the program:
fn main() {
let mut nums = vec![1, 3];
let mut counter = 0;
for mut p in nums.into_iter().cycle() {
println!("{}", p);
p += 1;
if p > 10 {
break;
}
counter += 1;
if counter > 1000 {
println!("ERROR");
break;
}
}
}
I expected this to print 1, 3, 2, 4, 3, 5, ... until it got to 10 and then halt. Instead, I got a warning:
warning: variable does not need to be mutable
--> src/main.rs:2:9
|
2 | let mut nums = vec![1, 2, 3];
| ----^^^^
| |
| help: remove this `mut`
|
And then an infinite loop (well, only finite because I added the counter in there). Why is this an infinite loop?
The behavior I wanted can also be written this way:
for idx in (0..nums.len()).cycle() {
let p = &mut nums[idx];
println!("{}", p);
*p += 1;
if *p > 10 {
break;
}
}
That works - but I don't want to iterate over the indices, I want to directly iterate over the values. Is there a way to write what I want?
The cycle() iterator adaptor works by cloning each of the values in the iterator so that they may be traversed multiple times. As this was applied on top of nums.into_iter(), the vector was fully consumed and p += 1 does not modify the vector retained in the cycle adaptor. The program would not end because no progress was being made.
You would want an iterator of mutable references, so that the vector is modified rather than consumed. But cycling an iterator of mutable references is not permitted because the adaptor needs to clone those references, which is illegal. A streaming iterator, which can handle incoming items in an exclusive fashion, would probably allow you to do this, but such an API is not usable without generic associated types (GATs).
One possible solution is not to use .cycle(): create an outer loop to traverse the vector multiple times and break explicitly on that loop once the intended condition arrives.
let mut nums = vec![1, 3];
let mut counter = 0;
'outer: loop {
for p in nums.iter_mut() {
println!("{}", p);
*p += 1;
if *p > 10 {
break 'outer;
}
counter += 1;
if counter > 1000 {
println!("ERROR");
break 'outer;
}
}
}
Playground
As mentioned by Stargateur in the comments, Vec::into_iter creates an iterator of the values in the vector. Iterator::cycle then clones the iterator each time it is exhausted:
fn cycle(self) -> Cycle<Self>
where
Self: Clone,
Instead of stopping at None, the iterator will instead start again, from the beginning. After iterating again, it will start at the beginning again. And again. And again. Forever.
Your code is effectively doing:
loop {
let mut p = 1;
p += 1;
}
This is also stated, indirectly, in two ways:
The unneeded mut warning from the compiler: the vector itself is never modified.
Your working example has a mutable reference that needs to be dereferenced: *p += 1. Your non-working version has a value.
You'd want to use iter_mut instead of into_iter. This will give you mutable references to values in the vector instead of consuming it. However, you cannot easily use cycle with iter_mut as mutable references cannot be copied; doing so could trivially lead to mutable aliasing, which is forbidden by Rust's rules of references.
The correct workaround is to use indices, as you have done.
See also:
Do all primitive types implement the Copy trait?
Mutable reference to container object within iterator loop
How to iterate over mutable elements inside another mutable iteration over the same elements?
How can I do a mutable borrow in a for loop?
What is the difference between iter and into_iter?
Problem Statement
I will try to elaborate the case by means of a scenario. Lets take this question for instance.
Link to question: https://leetcode.com/problems/remove-element/
Given an array nums and a value target, remove all instances of
that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example: Given nums = [0,1,2,2,3,0,4,2], target = 2; the output =
5 (number of elements not equal to target) and modify the array to
[0,1,3,0,4]
The order of elements can be changed. It doesn't matter what you leave
beyond the new length.
My Approach
Step-1: Identify all the elements which are equal to the given target and move them to right hand side of the array while maintaining a counter.
Step-2: Drop all the elements from right.
Step-3: return (n - counter), where n is the array length and counter is the number of elements equal to target.
Below is the implementation of the same:
object RemoveElement {
// Link to question: https://leetcode.com/problems/remove-element/
def main(args: Array[String]): Unit = {
var nums = Array(3,2,2,3)
val target = 3
val result = removeElement(nums, target)
// nums = nums.dropRight(_.equals(target)) // POINT 1
println(s"Result: ${result}, Modified Array: [${nums.mkString(", ")}]")
}
def removeElement(nums: Array[Int], target: Int): Int = {
val n = nums.length
var left, counter = 0
var right = n - 1
while(left < right){
if(nums(left) != target){
left += 1
}
else {
// Find position of the elements which is not equal to target
if(nums(right) == target){
counter += 1
right -= 1
}
else{
// Swap the elements
counter += 1
val temp = nums(left)
nums(left) = nums(right)
nums(right) = temp
left += 1
right -= 1
}
}
}
// nums.dropWhile(_.equals(target)) // POINT 2
// nums = nums.dropRight(_.equals(target)) // POINT 3
return (n - counter)
}
}
POINT - 1: Makes absolute sense as the array nums is in the scope of main method, therefore, the statement would work as charm.
POINT - 2: These lines has no impact to the array nums.
POINT - 3: Gives error. I understand that the input argument (array nums) is of type val (i.e. passed by reference, and hence immutable within the scope of the method removeElement).
If I had an option of creating a new array, there wouldn't be any issue. But if I am required to return the modified array by adding/removing the elements (like in this question) to the calling method, how do I achieve that in Scala?
To make the case more generic, what is the way by which we can modify the input collections (passed as arguments) in Scala methods?
P.S.: If I do not remove elements from the input array itself, LeetCode fails my submission with below message:
How do I modify an input array passed to a method by reference?
Scala does not support pass-by-reference. The default is pass-by-value (or more precisely, a special case of pass-by-value which is sometimes known as call-by-object, call-by-sharing, or call-by-object-sharing). Scala also supports call-by-name.
So, you simply cannot pass an array to a method by reference in Scala. You will have to use another language which supports pass-by-reference such as C# (with the ref keyword) or C++. (Note that Java also doesn't support pass-by-reference.)
Something like this
object Solution {
def removeElement(nums: Array[Int], `val`: Int): Int = {
var p: Int = 0
nums.foreach(v => {
if (v != `val`) {
nums(p) = v
p += 1
}
})
p
}
}
I'm getting used to the various data structures in Scala and I've noticed that this function (contrived example), which is supposed to move every character in the mutable array to the right by one, has no effect on the array:
def shiftRight(str: String): Array[Char] = {
val chars = str.toCharArray
for(i <- chars.length - 1 until 0) chars(i) = chars(i - 1)
chars
}
println(shiftRight("ABCD").mkString)
which produces the result
ABCD
not the expected
AABC
Default step for range is one. See class Range here and implicit that gets you to it here.
Instead of
for(i <- chars.length - 1 until 0)...
you need:
for(i <- chars.length - 1 until 0 by -1)...
I try to write a small application in go that takes 'x' numbers of integers from standard input, calculates the mean and gives it back. I have only gotten so far:
func main() {
var elems, mean int
sum := 0
fmt.Print("Number of elements? ")
fmt.Scan(&elems)
var array = new([elems]int)
for i := 0; i < elems; i++ {
fmt.Printf("%d . Number? ", i+1)
fmt.Scan(&array[i])
sum += array[i];
}............
When trying to compile this I get the following error message:
invalid array bound elems
What is wrong here?
You should use a slice instead of an array:
//var array = new([elems]int) - no, arrays are not dynamic
var slice = make([]int,elems) // or slice := make([]int, elems)
See "go slices usage and internals". Also you may want to consider using range for your loop:
// for i := 0; i < elems; i++ { - correct but less idiomatic
for i, v := range slice {
In my opinion, this results from confusion over the usage of the new and make functions. This is a known issue/feature in the Go language, as evidenced by several discussions about new vs make at golang-nuts.
The difference between new and make may become clearer by letting Go print out the type of the value created by new and make:
package main
import "fmt"
func main() {
fmt.Printf("%T %v\n", new([10]int), new([10]int))
fmt.Printf("%T %v\n", make([]int, 10), make([]int, 10))
}
The output:
*[10]int &[0 0 0 0 0 0 0 0 0 0]
[]int [0 0 0 0 0 0 0 0 0 0]
As can be seen from the type, to access an array element of new([10]int) we would first need to dereference the pointer.
Both new and make require a Go type as their 1st argument. However, the expression [elems]int is not a Go type (unless elems is a Go constant, which isn't the case here).
For further reference, see http://golang.org/doc/go_spec.html#Allocation and http://golang.org/doc/go_spec.html#The_zero_value.
To get a better understanding of whether the result of new is usable, it may be helpful to lookup whether len and cap work with zero (nil) values: http://golang.org/doc/go_spec.html#Length_and_capacity
See The Go Programming Language Specification
http://golang.org/ref/spec#Array_types
http://golang.org/ref/spec#Constants
It says:"The length is part of the array's type; it must evaluate to a non- negative constant representable by a value of type int. "
Constants by no means vary.