I'm attempting to create a list of lists to imitate the functionality of a 2D array in Dart, and I was having trouble for a while figuring out how to make it work.
I originally used List.forEach in order to create the lists and fill them, but after each loop, it's as if I never created the lists. Here's what that code looked like:
currentMap = new List<List<int>>(height);
currentMap.forEach((e) {
e = new List<int>(width);
e.forEach((f) {
f = 1;
});
});
Printing currentMap resulted in a list of null. Here's what I have now:
currentMap = new List<List<int>>(height);
for(int i = 0; i < height; i++) {
currentMap[i] = new List<int>(width);
for(int j = 0; j < width; j++) {
currentMap[i][j] = 1;
}
}
This works exactly as I expected it to.
I understand that this is probably a very basic issue, and I am assuming that forEach does not allow you to modify the element, but I wanted some confirmation on that, and the Dart API docs do not specify except with the phrase "apples the function f to each element..." which may just not be clear to me.
Also, I am aware of things like the List.filled() constructor -- this is just how I am starting to build towards other functionality.
EDIT: Okay, I think I understand now. Arguments are "pass-by-sharing" which means that a copy of a reference to the object is made. This means that you can modify a member of a mutable object that is pointed to by the argument (as follows):
void function(MyObject o) {
o.x = 5;
}
but trying to change what o points to will not change the argument after exiting the function, such as this:
void function(MyObject o) {
MyObject p = new MyObject();
o = p;
}
Dart does not have variable references, all elements are passed as a reference to an object, not to a variable. (In other words, Dart is purely "call-by-sharing" like both Java and JavaScript).
That means that the e parameter to the forEach callback is just a normal local variable, and assigning to it has no effect outside the callback. The same goes for iterators: they return the value in the iterable, but it has no reference back to the iterable after that.
The double loop is what you want when you do "read-modify-write". You read a value from the list, modify it and store it back into the list using the list's index-set operator.
I know you know about List.filled, but just for other readers, I'll give the one-liner to create the two-dimensional array initialized to 1 values:
currentMap = new List.generate(height, (_) => new List.filled(width, 1));
This is because e is only a reference to the List in currentMap not to a currentMap item.
You update a copy of the reference to a List, but this reference has no connection to currentMap.
After the loop, e just gets garbage collected.
This is because of how an Enumerator works and I believe because the Enumerator is immutable You can't modify the collection items when it's being processed in a foreach... removing members and such.
See also:
http://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx
What is the best way to modify a list in a 'foreach' loop?
Related
let mut args: Vec<String> = args().collect();
for mut i in 0..args.len() {
if args[i].contains("-type") {
project_type = args[i].split("=").last().unwrap();
args.remove(i);
i-=1;
}
}
I'm very new to rust and want to know why this code gives me the error "cannot borrow 'args' as mutable because it is also borrowed as immutable" and how i can fix it
I'm trying to check if the args Vec contains an item like "-type=some_type", then put "some_type" in a variable called "project_type". Finally I want to remove the item "-type=some_type" from the list and keep searching.
edit: if I'm doing what I'm trying to do wrong, i would appreciate a better solution.
str::split doesn't create new string objects, it returns references to the existing one. So your project_type variable is a reference to a string in args. When you remove from args, you invalidate all of those references.
You can convert a &str to a String and break the reference with .to_owned()
project_type = args[i].split("=").last().unwrap().to_owned();
Now, for loops in Rust iterate over data structures. As such, your i -= 1 trick won't work. i will just get reset back to where it was at the next iteration. If you want to do this the way you're currently doing it, you want a while loop.
let mut i = 0
while i < args.len() {
if ... {
...
} else {
i += 1;
}
}
However, let's think about this a bit more functionally. What it sounds like you want is to find a matching element of a vector (and its index) and then do something with it. So let's break that down into two separate problems.
We use enumerate to get a collection together with its index, and find to search it. Since it looks like you expect the value to be there, we'll unwrap it and panic if it's not there. If you want to handle the error, convert this to a match.
let (idx, element) = args.iter().find(|x| x.contains("-type")).unwrap();
Once we have it, we can do our work on element to get the project type.
project_type = element.split("=").last().unwrap().to_owned();
Note that at this point project_type does not depend on args at all. element does, and Rust may be smart enough to see this, but let's just be perfectly safe and make sure element gets dropped before we modify args. Once there are no more references to args, we can mutably borrow to do the remove operation.
let idx = {
let (idx, element) = args.iter().enumerate().find(|(_, x)| x.contains("-type")).unwrap();
project_type = element.split("=").last().unwrap().to_owned();
idx
}
args.remove(idx);
I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.
Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable
So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.
static void Main()
{
List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
(int, float)[] arr2 = new (int, float)[1];
arr1[0].Item1 += 1; // This line
arr2[0].Item1 += 1;
}
Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?
Why are tuple arrays mutable, but lists are not?
The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.
The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)
If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:
var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;
Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:
public void Method(ref int x) => x++;
public void CallMethod()
{
var list = new List<int> { 0 };
var array = new int[] { 0 };
Method(ref list[0]); // Error
Method(ref array[0]); // Valid
}
I have these two functions where i am trying to modify the elements. One of them compiles and other says 'val cannot be reassigned'. What is the difference between the following functions? Why does one compile and the other does not?
The one that compiles
fun <T> Array<T>.mapInPlace2(transform: (T) -> T) {
for (i in this.indices) {
this[i] = transform(this[i])
}
}
The one that says
Val cannot be reassigned
fun <T> Array<T>.mapInPlace1(transform: (T) -> T) {
for (i in this) {
i = transform(i);
}
}
Similiarly to how function parameters are final in Kotlin, so are the variables used in for loops. Essentially, writing down...
for (i in array) {
...
}
... is the equivalent of doing this in Java:
for (final int i : array) {
...
}
This helps catch some common errors, in this case - if the compiler allowed you - you'd be reassigning this local variable that just contains a reference to the real element, without changing the array. In Java terms, you'd be doing this:
for (int i : array) {
i = transform(i);
}
This new value of i is unused, it doesn't change the array itself, and it will be immediately overwritten by the value of the next element when the loop comes around.
Try this:
for(i:Int in 0 until this.size) {
this[i] = "your value"
}
You're confusing the mutability of references to objects and objects themselves.
In the first example, the structure is mutable, but the reference to it is immutable. You can change the structure of the object itself, but you can't change what structure the references points to.
In the second example, you're trying to change an immutable reference to an object, not the object itself.
If you write
val i = obj
obj can still be mutated if it's a mutable object. i can't be reassigned though, sine the reference can't be changed.
I want to read four cyclic measured sensors from an arduino and want to display the values with Processing.
My problem is, I get the error message: "Cannot find a class or type named 'Array' " in my processing code when I want to convert my data string into an array.
Does anybody know how to fix it?
import processing.serial.*;
Serial myPort;
String Messdaten;
String MessdatenSplit;
void setup () {
size(500, 500);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
}
void draw(){
}
void serialEvent(Serial myPort){
if (myPort.available() > 0){
String Messdaten = myPort.readStringUntil(3000);
if (Messdaten != null){
trim(Messdaten);
String MessdatenSplit[] = split(Messdaten,",");
MessdatenSplit = new Array[1400];
Natrium = new String[350];
Kalium = new Array[350];
Lithium = new Array[350];
Kupfer = new Array[350];
for (n=0; n<350; n++){
Natrium[n] = 1+4*n;
}
for (k=1; k<350; k++){
Kalium[k] = 1+4*k;
}
for (u=2; u<350; u++){
Kupfer[u] = 1+4*u;
}
for (l=3; l<350; l++){
Lithium[l] = 1+4*l;
}
}
}
}
There is no class named Array (well, there is, but it's not the one you want). That's not how you declare an array.
You declare an array variable by using the type of array you want, then using square brackets []. For example, you're declaring this variable:
String MessdatenSplit;
This declares the MessdatenSplit variable as String, not an array of Strings. Instead, you probably want this:
String[] MessdatenSplit;
Then when you initialize the MessdatenSplit variable, you should again use the type of array it is, and you should also use the square brackets and put the length of the array inside those square brackets. Here you're doing it correctly:
Natrium = new String[350];
(Although, you're missing a declaration for this variable, so you need to add that in for this to really work.)
The above line creates a String array with 350 indexes. But in this next line, and in a few other places, you're initializing it incorrectly:
MessdatenSplit = new Array[1400];
There is no Array keyword. You need to use the type of array it is, like this:
MessdatenSplit = new String[1400];
Note that you can also do the variable declaration and initialization in a single line:
String[] MessdatenSplit = new String[1400];
You might want to start over and declare and initialize a single array variable, then run it to make sure it works. Then add the next array, and run it to see if it works. You're running into trouble because you're trying to write and run your whole sketch at once, when really you need to be testing much smaller steps. Also, you should try to follow standard naming conventions: variables and functions should start with a lower-case letter.
So I'm having trouble figuring out how to compare two arrays for differences and be able to find which elements do not exist in each other. Most examples talk about object lookup for use with a "for each in" loop. That much makes sense, but I have no idea what is going on here:
var item:Sprite;
object_lookup[item] = true;
I'm quite confused because I've never seen anything other than an integer inside of [] such as with arrays.
Object is a dynamic, that means you can assign properties to it at runtime:
var o:Object = {};
o.sayHi = "Hi, it's me";
trace(o.sayHi); //traces: Hi, it's me
o.sayHiWithFunction = function () { return "Hi with function" };
trace(o.sayHiWithFunction()); //traces: Hi with function
If the property you want to assign is not a valid identifier, you have to use the [] and put it as a string, example:
var o:Object = {};
o.this = "Yes, it is this!"; // Error, this is a keyword! Won't compile
o["this"] = "And the correct this!"; //And this one works!
o["more words"] = "More words"; //Works too
Your code is confusing. If object_lookup is an Object instance, you created a property on it called null but you set this property to true. That means that it will have absolutely nothing to do with the Sprite item you declared above it. Which is null, of course, as you didn't assign a sprite object to it and that's why the property name gets evaluated to null. Do not confuse here: the property name "null" is just a string, it has nothing to do with the type null.
Now, the for in loop loops thru all the property names of an Object, and if you know the property names, you can actually look up the values, too. Looks something like this:
var o:Object = {a:"A", b:"B", c:"C"}; // This is equivalent to o.a = "A", o.b = "B", o.c = "C"... which is aquivalent to o["a"] = "A" ;)
for(var i in o) {
trace(i, o[i]) //traces: c C, a A, b B
}
The for each in is a bit different, if you trace i, you will see the values, not the property names as with for in loop.
Otherwise do what Vesper suggested you in the comment, read about Dictionary.