I would like to work in Ceylon with a multidimensional array. Is this planned in Ceylon? If so, how can I declare it?
I would like to use this construct in Ceylon, as shown here in Java:
int x = 5;
int y = 5;
String[][] myStringArray = new String [x][y];
myStringArray[2][2] = "a string";
First, consider whether you really need an array (i.e. something with fixed length and modifiable elements), or whether a list (or list of lists) or a map might be better. Though from your example, you seem to need modification.
In the JVM, a "multidimensional" array is just an array of arrays.
In Java, new String[y] creates an array filled with null entries, which is not an allowed value of type String in Ceylon. So you can either have an array of String? (which allows null), or pre-fill your array with some other value, using e.g. Array.ofSize(...):
Array.ofSize(y, "hello")
The same is valid for arrays of arrays. We could do this:
value myStringArray = Array.ofSize(x, Array.ofSize(y, "hello"));
Though this would have the same array in each "row" of the 2D-array, which is not what we want (as replacing myStringArray[2][2] would replace all entries with a 2 as the second coordinate). Here the other Array constructor is useful, which takes an iterable:
value myStringArray = Array({ Array.ofSize(y, "hello") }.repeat(x));
This takes advantage of the fact that the iterable enumeration evaluates its arguments lazily, and thus the array constructor will get x different elements.
I like Paulo's answer, but here's an alternative approach, which allows us to use a comprehension to populate the 2D array:
//the size of the square 2D array
value n = 5;
//create it using a nested comprehension
value arr = Array {
for (i in 1..n-1) Array {
for (j in 0..n-1)
i==j then 1 else 0
}
};
//display it
for (row in arr) {
printAll(row);
}
Related
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'm new in Kotlin, and I want to create a multi dimensional array of a custom class, with null permitted. Something like that
private var array_map = arrayOf<Array<Obstacle?>>()
...
array_map[1][2] = Obstacle()
How can I do it? Thank you!
In case you need the index of each element in the constructor of the elements of the array:
Declaration:
var matrix: Array<Array<Obstacle?>>
Instantiation and initialization:
matrix = Array(numRows) { row ->
Array(numCols) { col ->
Obstacle(row, col)
}
}
You can use private var arrayMap: Array<Array<Obstacle?>> = arrayOf(). Just wrap with as much Array<> as you need.
Not sure if this is what you want, but imagine that Obstacle is a custom class with a field num as below
data class Obstacle(var num: Int){}
A 2D array of the Obstacle object would be as below:
val array: Array<Obstacle?> = arrayOf(Obstacle(123), Obstacle(234))
val arrayOfArray: Array<Array<Obstacle?>> = arrayOf(array)
println(arrayOfArray[0][0]) // would print Obstacle(num=123)
println(arrayOfArray[0][1]) // would print Obstacle(num=234)
So you should be declaring your 2D array as below
val arrayOfArray: Array<Array<Obstacle?>> = arrayOf()
Your code will compile as is. The problem is just that array size can't be changed and arrayOf<Array<Obstacle?>>() creates an empty array, so array_map[1][2] = Obstacle() fails at runtime. (Unless you do array_map = ... somewhere between them. Note that you should prefer val arrayMap, which can't be reassigned, unless you have a specific reason to use var.)
If you want your array to start with nulls, there is arrayOfNulls in the standard library, but it only creates a single-dimensional array, and what you really need is an array of arrays of nulls. You can write a helper function:
inline fun <reified T> matrixOfNulls(n: Int, m: Int) = Array(n) { arrayOfNulls<T>(m) }
private val arrayMap = matrixOfNulls<Obstacle>(5, 5) // example arguments
The approach I always use for this case is:
arr2D = Array(sizeA) { Array(sizeB) { content } }
Note I replaced the sizes by fields names to illustrate that each number/field represents the width and height length of each dimension of the 2D array.
Also, content should be replaced by the main content you want to fill in each coordinate, in your case seems you aims to setup with Obstacle() instances. If you want fill this content in other moment put null or a quick Any() reference.
In this last case, after creating that you can simply perform to set the itens:
arr2D[1][2] = Obstacle()
I have a global 3D array declared like this:
TileType maps[DLVL_MAX][LEVEL_HEIGHT][LEVEL_WIDTH];
and a function in which I'd like to name one 2D slice of this array to make things less cumbersome, i.e. something like
void f(int dlvl) {
TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
...
}
At first sight this looks to me like it should be possible, since C array dimensions are ordered left to right. Yet I can't find the right expression for this. (Of course, I can just give level_map a TileType* type, but then I can't use double indexing as in level_map[x][y].)
Is it possible at all?
TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
&(maps[dlvl]) evaluates to an address, namely the address of the dlvlth element of maps.
You cannot use an address to initialise an array, which level_map is.
You could do
TileType (*plevel_map)[LEVEL_HEIGHT][LEVEL_WIDTH] = maps[dlvl];
The above statement defines and initialises plevel_map to point to the dlvlth element of maps.
You would then access the elements of dlvlth element of maps like this
(*plevel_map)[x][y]
Update
What you also could do is
TileType * pplevel_map = maps[dlvl][0];
And then access map[dlvl][0]'s element like this:
pplevel_map[x]
and then do
pplevel_map += sizeof(**maps);
to seek to maps[dlvl][1].
And then access map[dlvl][1]'s element (also) like this:
pplevel_map[x]
Update^2
To still be able access all "level"'s elements using [x][y] you could do:
TileType (*aplevel_map)[LEVEL_WIDTH] = maps[dlvl];
And then access map[dlvl]'s element like this:
aplevel_map[x][y]
TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
You can't do that because level_map is array, and array cannot be reassigned.
What you need is memcpy. Given what you need to assign to level_map is the first element of 3D maps (at index 0):
memcpy(level_map, &maps[0], sizeof(level_map));
You can do the same for other elements.
Edit:
I should have been clearer -- I'd like assignments to level_map elements to assign to the corresponding map element
Ok then you need to declare a pointer instead of array:
TileType (*level_map)[LEVEL_HEIGHT][LEVEL_WIDTH]; // pointer to 2D array
level_map = &maps[0]; // reassign pointer to the address of `maps` first element
Do yourself a favour
TileType maps[DLVL_MAX * LEVEL_HEIGHT* LEVEL_WIDTH];
Now always pass maps, and levelid (guess that's what you mean), y
co-ordinate, and x co-ordinate.
void foo(TileType *maps, int levelid, int x, int y)
{
TileType tile = BLANK;
map[levelid * LEVEL_HEIGHT * LEVEL_WIDTH + y * LEVEL_WIDTH + x]
= tile;
}
Then the problems just disappear.
The expression is a bit cumbersome, but you soon learn to live with it.
I have an array that takes in 2 types, a String and an Int the code looks like so
var totalDoubleSet1Array = [(Dante,10), (Cassius, 9), (Rio, 5)]
let sortedArray = totalDoubleSet1Array.sort { $0.1 > $1.1 }
I then use the sort function to arrange in order the highest score(Int) to the lowest with the name next to it. (So I can assign this to a string and display in an AlertAction)
I have seen it somewhere on here that yes I can print an Array of a single type of String or Int etc to the console but how can I Assign this array of 2 types (Stings and Ints) to a new Variable of String so I can assign it to a AlertAction message in swift please? Or even better how can I grab the individual element of each entry so I can assign it to a Var String? Hopefully this makes sense.. Thanks
This is not an "array of two types", it's an array of tuples. You can grab an item from the array and take its individual parts like this:
let (name, score) = totalDoubleSet1Array[i]
After this assignment you would get two variables - name of type String that has the value of i-th element's name, and score of type Int that has the value of i-th element's score.
If all you need is the name, you have two options:
You could use let (name, _) = totalDoubleSet1Array[i] syntax, or
You could use let name = totalDoubleSet1Array[i].1 instead.
Note that you are using the second syntax already in the comparison expression of your sorting function:
sort { $0.1 > $1.1 }
According Apple tuples are not the best choice for data structures...
Why not just using a custom struct
struct Player {
var name : String
var score : Int
}
let totalDoubleSet1Array = [Player(name:"Dante", score:10), Player(name:"Cassius", score:9), Player(name:"Rio", score:5)]
let sortedArray = totalDoubleSet1Array.sort { $0.score > $1.score }
Then you can easily access the name for example in a table view
let player = sortedArray[indexPath.row]
nameLabel.text = player.name
var arr = Array[Int](arr_size)
println(arr_size + " " + arr.size)
arr_size is 30 but arr.size is 1? Why is this?
I am trying to declare an empty array that I can fill in later at designated indexes.
Array[Int](arr_size) creates an array with one element, arr_size, and is commonly written as Array(arr_size), assuming arr_size type is Int.
Use this instead:
Array.ofDim[Int](arr_size).
You could also use more functional approach and fill the array directly during initialization, e.g. by Array.tabulate.
For creating an Array[Int] of a given size and initialize its values for instance to 0, consider also these other API based approaches,
var arr = Array.fill(arr_size)(0)
and
var arr = Array.tabulate(arr_size)(_ => 0)
Note type Int of 0 determines the type of the Array. Yet a full declaration with type includes
Array.fill[Int](arr_size)(0)
Array.tabulate[Int](arr_size)(_ => 0)
Alternatively you can do new Array[Int](arr_size)