I'm a total newbie in Dart and I've a lot of issues trying to change a member value of an Object inside a loop.
I've my object so defined:
class Cell {
int magicnum, x, y;
Cell(this.magicnum);
toString() {
return ("$magicnum - [$x][$y]");
}
}
I create a List of List of Cell (2d array) and then I need to fill x and y value according to position of each object in array.
for (int x = 0; x < DIM; x++) {
for (int y = 0; y < DIM; y++) {
grids[x][y].x = x;
grids[x][y].y = y;
}
}
This obviosly doesn't work because in Dart everything (also integer) is an Object and so, all Cell objects in my array have the same x and y value (they all got a reference to the same object).
How can I do?
Thanks
#julemand101
Array is made this way:
List<Cell> cells = List<Cell>.generate(DIM, (i) => Cell(i + 1));
List<List<Cell>> grids = List<List<Cell>>();
for (int i = 0; i < DIM; i++) {
grids.add(shuffleCell(cells));
}
You problem is you are not actually cloning each Cell object when you are doing the following (taken from the code example from comments):
List<Cell> newlist = List<Cell>.from(items);
Instead, you are creating a new List containing the same references to Cell objects as the previous list of items.
To create a copy of Cell objects you need to implement a clone method like:
class Cell {
int magicnum, x, y;
Cell(this.magicnum);
Cell.from(Cell cell)
: magicnum = cell.magicnum,
x = cell.x,
y = cell.y;
}
And do the following to iterate each element of the old list, create a new Cell object for each element and convert the result to a new List:
List<Cell> newlist = items.map((item) => Cell.from(item)).toList();
Related
I'm experiencing a ClassCastException with the following piece of code.
var temp = set.stream().flatMap(Arrays::stream).toArray(Token[]::new);
I also tried collecting into a set, but I got the same error.
var temp = set.stream().flatMap(Arrays::stream).collect(Collectors.toSet());
set is declared as a Set<Token[]>, but when debugging it says Set<Object[]>.
Edit:
I've narrowed down the issue to the method subsetsWithMinSize. Eventhough I call it with:
new Sets<Token>().subsetsWithMinSize(value, x);
it seems to return a Set<Object[]>. Can someone tell me why that is and how to fix it?
Here is the method subsetsWithMinSize:
public Set<T[]> subsetsWithMinSize(List<T> list, int min) {
Set<T[]> res = new HashSet<>();
for (int i = 0; i <= list.size() - min; i++)
for (int j = 0; list.size() - j >= i + min; j++) {
List<T> temp = new ArrayList<>();
for (int k = i; k < list.size() - j; k++) temp.add(list.get(k));
res.add((T[]) temp.toArray());
}
return res;
}
So after you guys helped me to minimise the search scope I found the issue.
When I was using (T[]) to cast it wouldn't work, because after type erasure T would just be cast to an Object. Here's the thread I found the answer on: How to properly return generic array in Java generic method?.
So to finally correct the code I had to change the method a little by using Array.newInstance() and put in Class<T> to make it work:
public Set<T[]> subsetsWithMinSize(Class<T> clazz, List<T> list, int min) {
Set<T[]> res = new HashSet<>();
for (int i = 0; i <= list.size() - min; i++)
for (int j = 0; list.size() - j >= i + min; j++) {
List<T> temp = new ArrayList<>();
for (int k = i; k < list.size() - j; k++)
temp.add(list.get(k));
var arr = (T[]) Array.newInstance(clazz, temp.size());
IntStream.range(0, temp.size()).forEach(k -> arr[k] = temp.get(k));
res.add(arr);
}
return res;
}
It uses Array.newInstance() to make T[] (cast is still necessary for the compiler) and then just copies temp into that array.
Another option would be to use lists instead of arrays, which is the better way.
Reference from Effective Java:
In Summary, arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased. As a consequcne, arrays provide runtime type safety but not compile-time type safety and vice versa for generics. Generally speaking, arrays and generics don’t mix well. If you find yourself mixing them and getting compile-time error or warnings, your first impulse should be to replace the arrays with lists.
The issue with that is that, for my use at least, lists use an unnecessarily big amount of space. Combined with the fact that I am making a powerset of the results later everything would just run super slow.
I have a List of the type Model. when I loop all its elements and loop the next one except for the last one, then change the last one manually, the one before changes.
here is a little code to reproduce the problem (also you can run it directly in dartpad from here)
void main() {
List<Model> s = [];
for (int i = 0; i < 5; i++) {
s.add(Model(i));
}
for (int i = 0; i < s.length - 1; i++) {
s[i] = s[i + 1];
}
print(s);
s[s.length-1].x = 100;
print(s);
}
class Model {
int x;
Model(this.x);
#override
String toString() => 'x: ' + this.x.toString();
}
notice that this problem does not happen when you comment out the for loop or the manual change, or instead of changing the last one's property, you reassign a new value to it, like s[s.length - 1] = Model(100);. seems like dart for some reason is re-running the loop.
When you run the second for loop, you assign the i + 1th Model to the ith position in the list:
// initialise list
for (int i = 0; i < s.length; i++) {
s[i] = s[i + 1]
}
If you unwrap the loop, it looks roughly like this:
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = s[4];
Notice that this leaves s[4] unchanged, but also assigns it to s[3].
In Dart, variables contain references to objects. This means that when your list runs s[3] = s[4];, both s[3] and s[4] point to the same object.
Now, if you modify s[4] you, are actually modifying the objects that s[4] refers to, which happens to also be the object that s[3] refers to, so they both appear to change in your list.
In my code, I'm creating a grid of objects. I'm trying to avoid duplication by abstracting away the loop that creates the grid and passing the specific object from outside. For example:
List<List<dynamic>> _createGridWithSameElements({
int height,
int width,
dynamic element,
}){
List<List<dynamic>> vanillaGrid = [];
for (int heightIndex = 0; heightIndex < height; heightIndex++){
List<dynamic> vanillaLine = [];
for (int widthIndex = 0; widthIndex < width; widthIndex++){
vanillaLine.add(element);
}
vanillaGrid.add(vanillaLine);
}
return vanillaGrid;
}
Then, if I wish to create a grid with string, I can:
List<List<dynamic>> emptyGrid = _createGridWithSameElements(
height: height,
width: width,
element: Cell.dead()
);
However, I would like to somehow recast the individual, atomic elements of the grid based on the type of the element. I think I have two options, neither of which I have been able to achieve:
Infer the type inside _createGridWithSameElements. But how would I do this without using List<List<dynamic>>?
Recast the grid after the _createGridWithSameElements function call. Is there a way to do this?
Use Generics to create an argument that can hold any type.
Don't forget to also, instead of passing the element itself, passing a function to generate instances of it. Otherwise you will have a grid containing the same repeated instance.
class Cell{}
void main(List arguments) {
final grid = _createGridWithSameElements(
height: 5,
width: 10,
elementGenerator: () => Cell()
);
print(grid.runtimeType); // List<List<Cell>>
}
List<List<T>> _createGridWithSameElements<T>({
int height,
int width,
T Function() elementGenerator,
}) {
final vanillaGrid = <List<T>>[];
for (int heightIndex = 0; heightIndex < height; heightIndex++) {
final vanillaLine = <T>[];
for (int widthIndex = 0; widthIndex < width; widthIndex++) {
vanillaLine.add(elementGenerator());
}
vanillaGrid.add(vanillaLine);
}
return vanillaGrid;
}
Some extra info to keep in mind:
The <T> after the function name is there to tell Dart to make T available as a generic type for that function. Any letter or word would be valid, though E, T, S, K, and V are the convention.
I'm looking to clone a row 3x, but only keeping data from one column.
So essentially I have the following [Name / Time / Booking], and each row is populated with all 3 properties, I'm trying to create 3 blank rows underneath each current row which is populated with only the persons name.
Can't work how to do it in scripting and can't find a plugin to do this. My data set is over 10,000 big so doing it manually isn't an option.
What I have:
What I want:
UPDATED code:
function duplicateRows() {
var sh, v, arr, c, b;
sh = SpreadsheetApp.getActive()
.getSheetByName('Blad1')
v = sh.getRange(1, 1, sh.getLastRow(), 40)
.getValues();
arr = [v[0]];
v.splice(1)
.forEach(function (r, i) {
arr.push(r)
c = 0
while (c < 3) {
dup = makeEmptyArrayXEl(40)
dup[0] = r[0];
arr.push(dup)
c += 1;
}
})
sh.getRange(1, 1, arr.length, arr[0].length)
.setValues(arr);
}
function makeEmptyArrayXEl(num) {
var arr = [];
for (var i = 0; i < num; i++) {
arr.push("")
}
return arr;
}
Would this work for you? It requires a free column to the left of Booking in the original data set. The formula below is a new sheet.
=ArrayFormula(sort({A2:A4,B2:B4,C2:C4;A2:A4,D2:D4,D2:D4;A2:A4,D2:D4,D2:D4;A2:A4,D2:D4,D2:D4},1,FALSE))
I have a method that fills up the elements of an int[,]. The elements that need to be filled are stored in a .txt file like this:
1
1
2
2
Meaning that I have to fill up the [1,1] and [2,2] element.
For this I use this but it gives the error above
int x = 0;
int y = 0;
for (int i = 0; i < 2; i++)
{
x = int.Parse(SR.ReadLine());
y = int.Parse(SR.ReadLine());
mezo.mezo[x, y] = 1;
}
Thanks in advance!
According to MSDN(http://msdn.microsoft.com/en-IN/library/b3h1hf19.aspx) a FormatException is thrown when:
s is not in the correct format.
s in your case is SR.ReadLine() which is returning some value that is not recognized as a number format.
At first look it might be because of whitespaces in your file.
Try
SR.ReadLine().Trim()
OR
NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite for the number style in the Parse method.