This method works fine. However, I think it is not functional.
fun getCopy(array: Array<BooleanArray>): Array<BooleanArray> {
val copy = Array(array.size) { BooleanArray(array[0].size) { false } }
for (i in array.indices) {
for (j in array[i].indices) {
copy[i][j] = array[i][j]
}
}
return copy
}
Is there a more functional way?
You can make use of clone like so:
fun Array<BooleanArray>.copy() = map { it.clone() }.toTypedArray()
or if you'd like to save some allocations:
fun Array<BooleanArray>.copy() = arrayOfNulls<ByteArray>(size).let { copy ->
forEachIndexed { i, bytes -> copy[i] = bytes.clone() }
copy
} as Array<BooleanArray>
or even more concise as suggested by #hotkey:
fun Array<BooleanArray>.copy() = Array(size) { get(it).clone() }
What about using copyOf()?
val copyOfArray = array.copyOf()
Returns new array which is a copy of the original array
Reference here
Related
I need to iterate over an array and change it's objects but I still need to reference the original array so that is why I need copy of the original array to change it's objects and then after completion of my operations I want to change the original array into the (copied) changed one. The size and objects are going to be the same but their values are going to change.
Thank you very much for your time and help in advance.
My problem is: when I copy the original array both copy and original are referencing the same locations in the memory so the state of the object changes and my code cannot complete it's tasks correctly. How can I copy an array so the copy references another locations in the memory but with identical objects?
Simple var copyArray = originalArray obviously doesn't work. I searched the web thorougly and I couldn't find exact answer to my problem in Kotlin.
Option 1:
Since your object only has one level of properties, a shallow copy is as effective as a deep copy. If it had more than one level you could still use copy() method but would have to specify explicitly how to copy each specific property.
val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.copy() } }
Full code:
fun main() {
val cell1 = Cell(true)
val cell2 = Cell(false)
val arrayA = arrayOf(cell1, cell2)
val arrayOfArrays = arrayOf(arrayA, arrayA)
val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.copy() } }
arrayOfArrays[0][0].isAlive = false;
arrayOfArrays.forEach { it.forEach { println("ArrayA: $it") } }
println()
arrayOfArrays2.forEach { it.forEach { println("ArrayB: $it") } }
}
Which results in:
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
Option 2:
You can serialize and deserialize the object.
Add the following dependency to build.gradle:
implementation 'com.google.code.gson:gson:2.9.0'
Make a deepCopy function inside your cell class:
import com.google.gson.Gson
data class Cell(
var isAlive: Boolean
) {
fun deepCopy(): Cell {
val json = Gson().toJson(this)
return Gson().fromJson(json, Cell::class.java)
}
}
And code to test it out with:
fun main() {
val cell1 = Cell(true)
val cell2 = Cell(false)
val arrayA = arrayOf(cell1, cell2)
val arrayB = arrayA.map { it.deepCopy() }.toTypedArray()
cell1.isAlive = false
println(arrayA.contentToString())
println(arrayB.contentToString())
}
Output:
[Cell(isAlive=false), Cell(isAlive=false)]
[Cell(isAlive=true), Cell(isAlive=false)]
Also, since you have a 2D array:
fun main() {
val cell1 = Cell(true)
val cell2 = Cell(false)
val arrayA = arrayOf(cell1, cell2)
val arrayOfArrays = arrayOf(arrayA, arrayA)
val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.deepCopy() } }.toTypedArray()
arrayOfArrays[0][0].isAlive = false;
arrayOfArrays.forEach { it.forEach { println("ArrayA: $it") } }
println()
arrayOfArrays2.forEach { it.forEach { println("ArrayB: $it") } }
}
Which results in:
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
input:
let arrayInt = [7,8,3,4,5,9,1,2,6]
output
let newArray = [1,2,3,4,5,6,7,8,9]
how to do that WITHOUT using .sort method that available in Swift? I just failed in programming test, so I want to know the answer :(
Hey look at this may help you, there are more then 1 possibilities:
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Sorting%20Algorithms/sorting.html
There is an example:
https://gist.github.com/tmdvs/d8edeb9bf26f2f5c3e50
EDIT: Here you have an example:
var unsortedArray = [7,8,3,4,5,9,1,2,6]
for i in stride(from: unsortedArray.count-1, to: 0, by: -1) {
for j in 1...i {
if unsortedArray[j-1] > unsortedArray[j] {
let tmp = unsortedArray[j-1]
unsortedArray[j-1] = unsortedArray[j]
unsortedArray[j] = tmp
}
}
}
After that the unsortedArray is sorted.
Bubble Sort
var unsortedArray = [7,8,3,4,5,9,1,2,6]
for i in 0..<unsortedArray.count {
for j in 0..<unsortedArray.count{
var temp = 0
if unsortedArray[i] < unsortedArray[j] {
temp = unsortedArray[i]
unsortedArray[i] = unsortedArray[j]
unsortedArray[j] = temp
}
}
}
print(unsortedArray)
I have a service which populates my associative array in typescript,
fun populateData(){
let tempArr;
tempArr = [];
this.service.get('Post', 1, 'true').subscribe(
(response) => {
this.loadingIcon = false;
for (let i = 0; i < response.results.length; i++) {
tempList = response.results[i]['tags'];
for ( let iter of tempList){
if ( iter in tempArr) {
tempArr[iter] = tempArr[iter] + 1;
}else {
tempArr[iter] = 1;
}
}
}
},
(error) => {
if (error['status'] === 401) {
localStorage.clear();
this.router.navigateByUrl('/login');
} else {
this.router.navigateByUrl('/error');
}
}
);
console.log(tempArr);
/*
This function is inside a class, once I iterate get access to tempArr I will be assigning the tempArr data to a class variable like
for (items in tempArr){
this.data.push(items, tempArr[items]);
}
*/
}
I'm able to populate my associative array with the service above which gives the following output in console,
I'm not able to iterate through this array, I tried a couple of methods like the following,
for ( const key in tempArr) {
console.log(key + ':' + tempArr[key]);
}
I want both they key and values from the array.
TypeScript generally assumes that the keys to arrays are numbers. What you were doing might work but it's not very idiomatic. I'm not going to rewrite your whole function but here are a few pointers:
When constructing your associative array (map for short from now on) you should try using an object instead of an array:
const tagCounts: { [key: string]: number } = {};
for (const result of response.results) {
for (const tag of result.tags) {
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
}
}
Then you can iterate the result with:
for (const tag of Object.keys(tagCounts)) {
const count = tagCounts[tag];
// Other stuff here
}
Or if you have polyfills for Object.entries then with:
for (const [tag, count] of Object.entries(tagCounts)) {
// Other stuff here
}
Looking at your code, this.data.push also seems wrong: it will add a string and a number to your data array which is almost certainly not what you want. You might want to consider converting data to an object as well if you want to store key-value pairs.
I have a Grid class which is wrapper over 2d array of Cell objects. I would like this class to implement Iterable<Cell> interface in order to use it in loops and iterate directly overall cells. Is there a simple way to do that? Does Kotlin support yield return style iterators? My current solution is quite verbose:
override fun iterator() = object : Iterator<Cell> {
val currentOuter = grid.iterator() // grid is object of Array<Array<Cell>>
var currentInner = if (currentOuter.hasNext()) currentOuter.next().iterator() else arrayOf<Cell>().iterator()
override fun next(): Cell {
if (!hasNext()) {
throw NoSuchElementException()
}
return if (currentInner.hasNext()) {
currentInner.next()
} else {
currentInner = currentOuter.next().iterator()
currentInner.next()
}
}
override fun hasNext(): Boolean {
return currentInner.hasNext() || currentOuter.hasNext()
}
}
Does Kotlin support yield return style iterators?
Yes, it does, through the feature of coroutines. Here's a self-contained example:
data class Cell(val d: Int)
val grid: Array<Array<Cell>> = arrayOf(arrayOf(Cell(1), Cell(2)), arrayOf(Cell(3), Cell(4)))
fun cellSequence() = buildSequence {
grid.forEach { it.forEach { yield(it) } }
}
fun main(args: Array<String>) {
cellSequence().forEach { println(it) }
}
Although this particular problem could have been simply solved with just a flatMap, the presented code can serve as a template to write any kind of procedural-looking code, for example:
fun complexCellSequence() = buildSequence {
yield(Cell(-1))
if (grid.size <= 2) {
yield(Cell(2))
}
for (row in grid) {
if (row.contains(Cell(1))) {
yield(Cell(1))
} else {
yield(Cell(12))
row.forEach { yield(it) }
}
}
}
This would be quite nontrivial to rewrite without coroutines.
A very simple solution would be something like this:
val grid: Array<Array<Cell>> = ...
override fun iterator() : Iterator<Cell> = grid.flatMap { it.asList() }.iterator()
Please take a look at my 2D-Array-Initialization. The code works.
class World(val size_x: Int = 256, val size_y: Int = 256) {
var worldTiles = Array(size_x, { Array(size_y, { WorldTile() }) })
fun generate() {
for( x in 0..size_x-1 ) {
for( y in 0..size_y-1 ) {
worldTiles[x][y] = WorldTile()
}
}
}
}
The problem is that it runs the initialization twice. Basically I want to instantiate the WorldTile-Object in the generate() function. So Line 3 shouldn't call "new WorldTile" there. How can I do that?
Also is that the proper Kotlin way of traversing a 2d-Array?
You can make worldTiles a lateinit property, and do all the initialization in the generate function:
class World(val size_x: Int = 256, val size_y: Int = 256) {
lateinit var worldTiles: Array<Array<WorldTile>>
fun generate() {
worldTiles = Array(size_x, {
Array(size_y, {
WorldTile()
})
})
}
}
If you try to access worldTiles before calling generate you will get an exception warning that it hasn't been initialized yet.
To initialise all to a fixed value:
// A 6x5 array of Int, all set to 0.
var m = Array(6) {Array(5) {0} }
To initialise with a lambda:
// a 6x5 Int array initialise i + j
var m = Array(6) { i -> Array(5) { j -> i + j } }
Another way: Here is an example of initialising a 2D array of Float numbers (3 by 6):
var a = Array(3) { FloatArray(6)} // define an 3x6 array of float numbers
for(i:Int in 0 until a.size) {
for(j : Int in 0 until a[i].size) {
a[i][j] = 0f // initialize with your value here.
}
}
val twoDimStringArray= arrayOf(
arrayOf("first","second"),
arrayOf("foo"),
arrayOf("bar","great kotlin")
)
for (i in twoDimStringArray){
for(j in i){
println(j)
}
}
first
second
foo
bar
great kotlin
A bit late but could help to somebody if is working with strings
//init 2d array with a fixed size:
var data2 = Array<Array<String>>(2) { arrayOf()}
// fill the 2d array
data2[0] = arrayOf("123","Freddy x","27")
data2[1] = arrayOf("124","Elon y","45")
cheers!