I want to take coordinates and add them to an array that i want to return from a function but i don't know how to append in kotlin to an empty array with another array
var temp:Array<Array<Int>> = arrayOf<Array<Int>>()
var i:Int = 0
while (true){
// if you see another of the same type then break
if(currentPlayer == 1){
if(ystart-i < 0){ // if you would go out of bounds on the next it and the current one does not have an opposite then breakwith temp as nothing
temp = arrayOf<Array<Int>>()
break
}else if(touchnum[ystart-i][xstart] == 1){
break
}else{
val slice: IntArray = intArrayOf(xstart, ystart-i)
temp.plusElement(slice)
}
}else{
}
Arrays are of fixed length on the JVM. Once created, you can't change their length.
The equivalent concept for dynamically growing arrays is called a list.
In Kotlin, they are represented by the MutableList interface (or List when you need a read-only reference).
You can create an instance of MutableList with the function mutableListOf<T>() (where T is the type of the elements in the list). Then you add elements using list.add(element).
That was for your "main" list. Now let's talk about the elements you put in it.
In Kotlin it is not very idiomatic to represent tuples (like coordinates) as arrays. For 2D coordinates, there is already a type called Pair<A, B>. But honestly it's so cheap to write a domain-specific class yourself that I encourage you to create your own, such as:
data class Point2D(val x: Int, val y: Int)
And then you can add instances of this class to your list:
list.add(Point2D(xstart, ystart-i))
Related
I am using as3 in adobe animate to create a video game.
I have created multiple arrays with movie clips e.g.
var A:Array [mc1, mc2, mc3]
var B:Array [mc4, mc5, mc6]
var C:Array [mc7, mc8, mc9]
var anObject:DisplayObject;
How can I operate all movie clips in all arrays simultaneously?
I have tried this:
mc_Player.addEventListener(MouseEvent.CLICK, Change_Position);
function Change_Position (event:MouseEvent):void
{
{for each (anObject in A) & (anObject in B) & (anObject in C) // how can I get this right?
{anObject.x -= 100;
}}
}
I am also trying to understand if there is a way to operate all movie clips in my project simultaneously without using arrays.
e.g.
mc_Player.addEventListener(MouseEvent.CLICK, Change_Position);
function Change_Position (event:MouseEvent):void
{
{all movie_clips // how can I get this right?
{anObject.x -= 100;
}}
}
Thank you.
There's no such thing as simultaneous in programming (well, unless you are multi-threading with the perfect sync, which is not an AS3 story at all).
There are to ways to get close to that simultaneous thing:
Put all the objects into a single container. You will be able to change x and y of that container so all the in-laid objects will change their visible positions at once. The downside is that you cannot rotate or scale them individually (think of them as clipped to a board and imagine you rotate the whole board), or you won't be able to move half of them.
Arrays and loops. You iterate through all the items one by one, very fast. It looks simultaneous from the outside, but it never is.
All that said, in order to achieve the things you want you need to figure a way to put all the objects you want to process simultaneously into a single Array and then do the thing you want on them.
Case №1: many Arrays to one.
// This methods takes a mixed list of items and Arrays
// and returns a single flattened list of items.
function flatten(...args:Array):Array
{
var i:int = 0;
// Iterate over the arguments from the first and on.
while (i < args.length)
{
if (args[i] is Array)
{
// These commands cut the reference to the Array
// and put the whole list of its elements instead.
aRay = [i,1].concat(args[i]);
args.splice.apply(args, aRay);
}
else
{
// The element is not an Array so let's just leave it be.
i++;
}
}
return args;
}
Then all you need to do is to get a single list out of your several Arrays:
var ABC:Array = flatten(A, B, C);
for each (var anObject:DisplayObject in ABC)
{
anObject.x -= 100;
}
Performance-wise, it is a good idea to pre-organize, if logically possible, these Arrays so you don't have to compile them each time you need to process all the objects. Simply, if sometimes you would need A + B, and sometimes B + C, and sometimes A + B + C, just create them and have them ready. If you know what you are going to deal with, you won't even need that complicated flatten method:
var AB:Array = A.concat(B);
var BC:Array = B.concat(C);
var ABC:Array = A.concat(B).concat(C);
Case №2: all the children at once. As I already explained in my answer to one of your previous questions, you can iterate over all the children of a certain container, and you can put them into — guess what — Array for later use. Also, you can filter the objects while doing so and put only those ones you actually want to be there.
var ALL:Array = new Array;
// Iterate over the amount of children of "this" container.
for (var i:int = 0; i < numChildren; i++)
{
// Obtain a reference to the child at the depth "i".
var anObject:DisplayObject = getChildAt(i);
// Here go possible criteria for enlisting.
// This will ignore texts and buttons.
// if (anObject is MovieClip)
// This will take only those with names starting with "mc".
if (anObject.name.substr(0, 2) == "mc")
{
ALL.push(anObject);
}
}
// Viola! You have all the objects you want in a single Array
// so you can bulk-process them now, which is ALMOST simultaneous.
I know you shouldn't, I kind of know why. But I mean I don't understand my own code once I am trying really to think what's going on.
So I have an array with bunch of objects. I am iterating over it and once I find an object with specific type, I remove it from the array, and add another object into the array. So something like this:
var arr = parent.allchildren() //getting all the children in array
for ele in arr{
if(ele==somethingHere){
parent.remove(ele)
parent.add(new ele) //add new child into child array
}
}
If I have an array of 1,2,3,4,5, and I remove 3 and add a 6 while iterating, the actual array would be 1,2,4,5,6 but the array I am iterating would still be 1,2,3,4,5.
Which I think it would be fine, because at the end I still get what I want, which removed the element and added the element I need. However modifying the list while iterating it is bad and you shouldn't do that, but for my case I think it does what I need. What could be the potential issue in my case that I can't see?
One thing you may want to think about doing is making all of the changes at the end of the iteration. Instead of making the changes one by one, record the changes you want to make while iterating, and then actually make those changes once your loop is finished.
For example, you could make an array of elements to remove, and an array of elements to add.
//Our array where we record what we want to add
var elementsToAdd = [Any]()
//Our array of what elements we want to remove. We record the index at
//which we want to remove the element from the array
var indexesToRemoveAt = [Int]()
//Getting all the children in array
var arr = parent.allchildren()
//Enumerating an array allows us to access the index at which that
//element occurs. For example, the first element's index would be 0,
//the second element's index would be 1, the third would be 2, and so
//on
for (index,ele) in arr.enumerated() {
if(ele == somethingHere) {
indexesToRemoveAt.append(index)
elementsToAdd.append(newEle)
}
}
//Now that we have recorded the changes we want to make, we could make
//all of the changes at once
arr.remove(at: indexesToRemoveAt)
arr.append(contentsOf: elementsToAdd)
Note that removing array elements at multiple indexes would require the following extension to Array. If you wanted to avoid creating this extension, you could always just loop through the array of indexes and tell the array to remove at each individual index. All this extension function is really doing is looping through the indexes, and removing the array element at said index.
Array extension to remove elements at multiple indexes:
extension Array {
//Allows us to remove at multiple indexes instead of just one
mutating func remove(at indexes: [Int]) {
for index in indexes.sorted(by: >) {
if index <= count-1 {
remove(at: index)
}
}
}
}
I just tested in a playground with the following code:
var arr = ["hi", "bye", "guy", "fry", "sky"]
for a in arr {
if arr.count >= 3 {
arr.remove(at: 2)
}
print(a)
}
print(arr)
This prints:
hi
bye
guy
fry
sky
["hi", "bye"]
So it looks like when you use a for-in loop in Swift, the array is copied and changes you make to it will not affect the array you are iterating over. To answer your question, as long as you understand that this is the behavior, there's nothing wrong with doing this.
I have a small bit of code that looks like this:
func initAllLabels() {
var scoreLabels:[[[SKLabelNode]]] = []
for (var x = 0; x < modesInGame; x++) {
for (var y = 0; y < levelsInMode; y++) {
for (z = 0; z < labelsInLevel; z++) {
scoreLabels[x][y][z] = SKLabelNode(fontNamed: "Font")
}
}
}
}
So what I am trying to do is store all my labels for every game mode. The reason I'm trying to use a multidimensional array is because I will have several labels per level (3-5) and I would like to access them like this:
updateText(scoreLabels[currentMode][currentLevel][thisLabel])
And accessing all the labels for the current label like this:
for label in labelsInLevel:
label.hidden = false
The problem is that when I try to create all my labels at the start of the game in initAllLabels, I get an "index out of range" error at the first run in the loop (index: 0). I think the problem is because I need to "append" to the array before setting its contents, is this right? How would I accomplish this in an array structure like mine?
You need to initialize the array to a given size before updating items at positions within it. It might help to start with the single-dimensional case:
var labels: [SKLabelNode] = [] // creates an empty array
// since the array is empty, this will generate an index out of range error:
labels[0] = SKLabelNode(fontNamed: "Font")
Instead you need to extend the array with the elements you want to add. For example,
for _ in 0..<labelsInLevel {
labels.append(SKLabelNode(fontNamed: "Font"))
}
(the _ means “I don’t care about the actual number of each iteration - normally if you wanted to know this was the ith time around the loop you’d write for i in 0..<n)
There are nicer ways to do this though. But be careful with one of them, the initializer for Array that takes a count and a repeatedValue:
let labels = Array(count: labelsInLevel, repeatedValue: SKLabelNode(fontNamed: "Font”))
SKLabelNode is a reference type. That means that a variable only refers to an instance, and assigning one variable to another only copies the reference. So for example:
let variableOne = SKLabelNode(fontNamed: "Foo")
let variableTwo = variableOne
// variableTwo now refers to the same instance of SKLabelNode
variableTwo.fontName = "Bar"
print(variableOne)
// fontName will now be “Bar” even though this was
// done via variableTwo
You get the same effect with the repeatedValue code above. The label is created once, and the same reference to it is inserted multiple times. Change a property on one label in the array, and you change them all. Note the for loop version does not have this problem. Every time around the loop, a new SKLabelNode instance will be created. They won’t be shared.
An alternative to the repeatedValue initializer, that creates without using a for loop is to use map:
(0..<labelsInLevel).map { _ in SKLabelNode(fontNamed: "Font") }
Here, just like in the for loop version, a new SKLabelNode instance is created every time.
(again, we use the _ to indicate we don’t care about the number of the iteration)
Finally, to create the nested multidimensional arrays with the loops inside, you can run map multiple times:
var scoreLabels =
(0..<modesInGame).map { _ in
(0..<levelsInMode).map { _ in
(0..<labelsInLevel).map { _ in
SKLabelNode(fontNamed: "Font")
}
}
}
You need to initialize the 3D array like this if you want all SKLabelNode to point at different SKLabelNodes :
func initAllLabels() {
var scoreLabels = [[[SKLabelNode]]](count: modesInGame, repeatedValue:
[[SKLabelNode]](count: levelsInMode, repeatedValue:
(0..< labelsInLevel).map { _ in SKLabelNode(fontNamed: "Font") }))
}
The repeatedValue is what you are storing in the cells (type or value) and the count represent the number of times you want to store it in your array.
PS: This answer was tested with Xcode Playground and works perfectly fine.
I edited my answer following Airspeed Velocity's comment.
I'm new to scala/java and I have troubles getting the difference between those two.
By reading the scala doc I understood that ArrayBuffer are made to be interactive (append, insert, prepend, etc).
1) What are the fundamental implementation differences?
2) Is there performance variation between those two?
Both Array and ArrayBuffer are mutable, which means that you can modify elements at particular indexes: a(i) = e
ArrayBuffer is resizable, Array isn't. If you append an element to an ArrayBuffer, it gets larger. If you try to append an element to an Array, you get a new array. Therefore to use Arrays efficiently, you must know its size beforehand.
Arrays are implemented on JVM level and are the only non-erased generic type. This means that they are the most efficient way to store sequences of objects – no extra memory overhead, and some operations are implemented as single JVM opcodes.
ArrayBuffer is implemented by having an Array internally, and allocating a new one if needed. Appending is usually fast, unless it hits a limit and resizes the array – but it does it in such a way, that the overall effect is negligible, so don't worry. Prepending is implemented as moving all elements to the right and setting the new one as the 0th element and it's therefore slow. Appending n elements in a loop is efficient (O(n)), prepending them is not (O(n²)).
Arrays are specialized for built-in value types (except Unit), so Array[Int] is going to be much more optimal than ArrayBuffer[Int] – the values won't have to be boxed, therefore using less memory and less indirection. Note that the specialization, as always, works only if the type is monomorphic – Array[T] will be always boxed.
The one other difference is, Array's element created as on when its declared but Array Buffer's elements not created unless you assign values for the first time.
For example. You can write Array1(0)="Stackoverflow" but not ArrayBuffer1(0)="Stackoverflow" for the first time value assignments.
(Array1 = Array variable & ArrayBuffer1 = ArrayBuffer variable)
Because as we know, Array buffers are re-sizable, so elements created when you insert values at the first time and then you can modify/reassign them at the particular element.
Array:
Declaring and assigning values to Int Array.
val favNums= new Array[Int](20)
for(i<-0 to 19){
favNums(i)=i*2
}
favNums.foreach(println)
ArrayBuffer:
Declaring and assigning values to Int ArrayBuffer.
val favNumsArrayBuffer= new ArrayBuffer[Int]
for(j<-0 to 19){
favNumsArrayBuffer.insert(j, (j*2))
//favNumsArrayBuffer++=Array(j*3)
}
favNumsArrayBuffer.foreach(println)
If you include favNumsArrayBuffer(j)=j*2 at the first line in the for loop, It doesn't work. But it works fine if you declare it in 2nd or 3rd line of the loop. Because values assigned already at the first line now you can modify by element index.
This simple one-hour video tutorial explains a lot.
https://youtu.be/DzFt0YkZo8M?t=2005
Use an Array if the length of Array is fixed, and an ArrayBuffer if the length can vary.
Another difference is in term of reference and value equality
Array(1,2) == Array(1,2) // res0: Boolean = false
ArrayBuffer(1, 2) == ArrayBuffer(1,2) // res1: Boolean = true
The reason for the difference is == routes to .equals where Array.equals is implemented using Java's == which compares references
public boolean equals(Object obj) {
return (this == obj);
}
whilst ArrayBuffer.equals compares elements contained by ArrayBuffer using sameElements method
override def equals(o: scala.Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (
o match {
case it: Seq[A] => (it eq this) || (it canEqual this) && sameElements(it)
case _ => false
}
)
Similarly, contains behaves differently
Array(Array(1,2)).contains(Array(1,2)) // res0: Boolean = false
ArrayBuffer(ArrayBuffer(1,2)).contains(ArrayBuffer(1,2)) // res1: Boolean = true
Let's say I have 4 arrays:
[1,3,54,4]
[54,2,3,9]
[3,2,9,54]
[54,8,4,3]
I need to get the objects (in this case integers but they will be custom object) that are present in (common to) all of the arrays. In the case above I would need the result to be: [54,3] as those are the only items two that are in all four arrays.
Order does not matter, speed matters greatly, array sizes and the number of arrays will vary greatly.
I'm using C# 4 and ASP.NET. The arrays will be List although they could just be converted.
Thanks :)
How about:
ISet<int> intersection = new HashSet<int>(firstArray);
intersection.IntersectWith(secondArray);
intersection.IntersectWith(thirdArray);
intersection.IntersectWith(fourthArray);
Note that this should be more efficient than the more obvious:
var x = firstArray.Intersect(secondArray)
.Intersect(thirdArray)
.Intersect(fourthArray);
as the latter will create a new hash set for each method call.
Obviously with multiple arrays you'd just loop, e.g.
static ISet<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> collections)
{
using (IEnumerator<T> iterator = collections.GetEnumerator())
{
if (!iterator.MoveNext())
{
return new HashSet<T>();
}
HashSet<T> items = new HashSet<T>(iterator.Current);
while (iterator.MoveNext())
{
items.IntersectWith(iterator.Current);
}
return items;
}
}