Kotlin initialize an Array using another array - arrays

I can initialize an array in Kotlin like this:
val mArr = Array<Int>(5) {0}
and I'll have the following array [0,0,0,0,0]
The thing is, I need to initialise an array and put the values of another array into it.
i.e:
initialArray = [1, 4, 5 ,-2, 7]
val offset = 5
And should get mArr = [6, 9, 10, 3, 12]
Is there a way to set the value of each mArr[i] based on each initialArray[i]?
Something like
val mArr = Array<Int>(initialArray.size) { offset + initialArray[index]}
Without wrapping it in a for loop

There is map function for array.
So:
val initialArray = arrayOf(1, 4, 5 ,-2, 7)
val offset = 5
val newArray = initialArray.map { it + offset }.toTypedArray()
But this way you create new array without modifying the old one.
If you want modify old array you can use forEachIndexed extension method:
initialArray.forEachIndexed { index, value ->
initialArray[index] = initialArray[index] + offset
// or:
initialArray[index] = value + offset
}

val mArr = Array<Int>(initialArray.size) { offset + initialArray[index] }
already nearly works. It's just that index isn't defined here. You want it to be the function's parameter, so { index -> offset + initialArray[index] } or shorter { offset + initialArray[it] }. Also, for this you probably want IntArray instead of Array<Int> (and for initialArray as well). Combining these changes:
val mArr = IntArray(initialArray.size) { offset + initialArray[it] }

Related

Swift : Performing operations on certain elements of an array

So, something is bugging me with the syntax in Swift for performing operations on Arrays of Ints.
What I wanna do is this : I have an array of Ints which is outputted from a function, its size (count) varies between say 2 and 6 for now, depending on buttons I press in my app.
For each array that is outputted and that contain n ints, I want to create n arrays on which to perform an other action later on.
These "sub" arrays are supposed to be calculated this way :
newArray1's values should be array's values - the value of the first index of newArray1
newArray2's values should be array's values - the value of the second index of newArray2
etc... (I'll automate the number of newArrays according to the array.count)
An other condition applying for those new arrays is that if at a given index the value is negative, I add 12 (so it'll occur for newArray2 at index 1, for newArray3 at indexes 1 & 2, etc... as long as those newArrays are created).
Here's how I wanted to perform that (I created this with dummy arbitrary array in the playground for the sake of testing before inserting the correct stuff in my app code) :
var array : [Int] = [2,4,6,8,9]
var newArray2 = [Int]()
var increment2 = Int()
increment2 = array[1]
newArray2 = array.map {$0 - increment2}
for i in 0..<newArray2.count {
if array[i] < 0 {
newArray2[i] = array[i] + 12
} else {
newArray2[i] = array[i]
}
}
print(array)
print(newArray2)
So of course it doesn't work because I can't seem to figure how to correctly perform operations on Arrays...
Intuitively it seems in my first if statement I'm comparing not the element at index i but i itself, not sure how to reformat that though...
Any help is most welcome, thanks in advance ! :)
[EDIT: I just edited the names of newArray1 to newArray2, same for increments, so that I have negative values and it matches the index value of 1 which is the second element of my main array]
You seem to mean this:
let arr = [2,4,6,8,9]
var results = [[Int]]()
for i in arr.indices {
results.append(arr.map {
var diff = $0-arr[i]
if diff < 0 { diff += 12 }
return diff
})
}
// results is now:
// [[0, 2, 4, 6, 7],
// [10, 0, 2, 4, 5],
// [8, 10, 0, 2, 3],
// [6, 8, 10, 0, 1],
// [5, 7, 9, 11, 0]]

Swift define datatype of array

I need to somehow cast a 2dimensional array...
console:
solution.swift:22:23: error: missing argument label 'arr:' in call
array = invertArr(arr)
^
arr:
solution.swift:53:12: error: cannot convert return expression of type '[[Any]]' to return type '[[Int]]'
return result
^~~~~~
as! [[Int]]
and that's the code:
func invertArr(arr:[[Int]]) -> [[Int]]{
var counter = 0
var result = [[]]
for element in arr{
if counter == 0{
continue
}
var counter2 = 0
for item in element.reversed(){
result[counter][counter2] = item
counter2 += 1
}
counter += 1
}
return result
}
Thank you for helping!
Because of two serious issues your code cannot work anyway even if you call the method with the arr parameter label and declare result as [[Int]]().
As counter is 0 the first loop continues always and an empty array is returned.
result[counter][counter2] = item crashes reliably because there are no items at the given indices.
To invert the order of the items in the inner arrays this is a generic version
func invertArr<T>(arr: [[T]]) -> [[T]]{
var result = arr
for (index, element) in arr.enumerated() {
result[index] = element.reversed()
}
return result
}
let array = [[1, 2, 3, 4], [5, 6, 7, 8]]
let inverted = invertArr(arr: array) // [[4, 3, 2, 1], [8, 7, 6, 5]]
If you want to reverse also the items in the outer array return result.reversed()

How to find a random index in array A which value does not appear in array B?

Let's say array A holds this:
[0, 1, 8, 3, 10, 6, 2]
And array B holds this:
[1, 2]
How can I generate a random index in array A which value does not appear in array B? Possible indexes in above example are:
0, 2, 3, 4, 5
But how to do this in Swift?
When you want to work with Array elements and their indices, enumerated() can be a good tool:
var a = [0, 1, 8, 3, 10, 6, 2]
var b = [1, 2]
var possibleIndices = a.enumerated()
.filter{!b.contains($0.element)}
.map{$0.offset}
print(possibleIndices)
//->[0, 2, 3, 4, 5]
(When b can be large, better make it a Set.)
And then:
(When we can assume b never holds all contents of a.)
var randomIndexToPossibleIndices = Int(arc4random_uniform(UInt32(possibleIndices.count)))
var randomIndex = possibleIndices[randomIndexToPossibleIndices]
If the assumption above cannot be satisfied, possibleIndices can be empty. So you'd better make randomIndex Optional:
var randomIndex: Int? = nil
if !possibleIndices.isEmpty {
var randomIndexToPossibleIndices = Int(arc4random_uniform(UInt32(possibleIndices.count)))
randomIndex = possibleIndices[randomIndexToPossibleIndices]
}
Thanks for Martin R.
First, you'd have to generate a diff between the 2 arrays ( unless they're both extremely large, in which case randomly trying recursively might result in better performance ).
Then all you have to do is find a random index you'd like to use and access said element:
#if os(Linux)
let j = Int(random() % ((count-1)))
#else
let j = Int(Int(arc4random()) % ((count-1)))
#endif
Will give you a proper index
If you then use this index and the element to find original element in your array you'll have your result.
If in case your elements are integers, and thus collisions can occur the thing I'd do would be recursively finding it to solve your problem. Remember that this can result in slow performance.
Look into the functional programming part of collections in swift here:
Swift Guide to map filter reduce
For instance you could use filter in the following way ( and I don't know if this is the best way ):
collection.filter {
var found = false;
for element in bCollection {
if element == $0 {
found = true;
}
}
return !found; // Might be better to turn true/false thing around in the above code to slightly improve performance.
}
How about working with sets?
let a = [0, 1, 8, 3, 10, 6, 2]
let b = [1, 2]
var setA = Set(a)
var setB = Set(b)
setA.subtract(setB)
var index: Int? = nil
if let first = setA.first {
index = a.index(of: first)
}
// if index == nil no such index exists

Groupby Array[Array[String]] Scala

I have an Array[Array[String]] like this:
Array(Array("A","1","2"),
Array("A","3","4"),
Array("A","5","6"),
Array("B","7","8"),
Array("B","9","10"))
I would like to groupby on the first element of each sub Array and get a Map like this:
var A:Map[String, Array[String] = Map()
A + = ('A' -> Array("1", "2"))
A + = ('A' -> Array("3", "4"))
A + = ('A' -> Array("5", "6"))
A + = ('B' -> Array("7", "8"))
A + = ('B' -> Array("9", "10"))
I don't know how to manipulate groupby to get this result.
Do you have any idea?
Try this.
val arr = Array(Array("A","1","2"),
Array("A","3","4"),
Array("A","5","6"),
Array("B","7","8"),
Array("B","9","10"))
val result = arr.groupBy(_.head).map{case (k,v) => k -> v.flatMap(_.tail)}
result("A") // Array(1, 2, 3, 4, 5, 6)
result("B") // Array(7, 8, 9, 10)
Basically, after grouping you need to remove the head of each sub-array (that's the tail part), and you need to flatten the sub-arrays into a single array (that's the flatMap part).
Warning: this will throw a runtime exception if any of the sub-arrays are empty. Here's a version that will take care of that.
val result=arr.groupBy(_.headOption).collect{case (Some(k),v)=>k->v.flatMap(_.tail)}

How do I fetch the i'th element from a Swift ArraySlice?

Below I am trying to fetch the i'th element of the ArraySlice draggignFan. The code builds fine (no warnings) but the program dies at runtime on the line where I try to index the slice like a normal array:
var draggingFan : ArraySlice<Card>?
...
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[i] // EXECUTION ERROR HERE
...
}
}
According to the docs there is a first and last method (which I use elsewhere with no problem). So how do I index an ArraySlice in Swift? (Note: I am intentionally skipping the 0'th index in the slice -- that's needed elsewhere).
The indices of the ArraySlice still match those of the original array. In your case, you are accessing index 1 which is not in your slice. If you offset the index by draggingFan.startIndex it will work:
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[draggingFan.startIndex + i]
...
}
}
Alternatively:
if let draggingFan = draggingFan {
for i in draggingFan.startIndex + 1 ..< draggingFan.endIndex {
let card = draggingFan[i]
...
}
}
This will access the values from the second element in the slice to the last element in the slice:
let original = [1,2,3,4,5,6] // Int array to demonstrate
var draggingFan : ArraySlice<Int>?
draggingFan = original[1...4] // create the slice
if let draggingFan = draggingFan {
// so there's no errors just slice the slice and iterate over it
for i in draggingFan[(draggingFan.startIndex+1)..<draggingFan.endIndex] {
print(i, terminator: ", ")
}
}
Output:
3, 4, 5,
The reason you are having this problem is that the slice maintains the original index numbers of the sequence you got it from. Thus, element 1 is not in this slice.
For example, consider this code:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
Now what is slice[1]? It isn't 4, even though that is the second thing in the slice. It's 2, because the slice still points into the original array. In other words, slice[1] is out of the slice's range! That is why you're getting a runtime error.
What to do? Well, the actual indexes of the slice are its indices. That is what you want to cycle thru. But... You don't want the first element pointed to by the slice. So you need to advance the startIndex of the range you're going to iterate through. Thus:
if let draggingFan = draggingFan {
var ixs = draggingFan.indices
ixs.startIndex = ixs.startIndex.advancedBy(1)
for i in ixs {
// ... now your code will work ...
}
}
However, in my view, there's no need to index the slice at all, and you shouldn't be doing so. You should cycle through the slice itself, not thru its indexes. You have this:
for i in 1 ..< draggingFan.count
But that is much like saying
for aCard in draggingFan
...except that you want to drop the first element of the slice. Then drop it! Say this:
for aCard in draggingFan.dropFirst()
To see that this will work, try this in a playground:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
for anInt in slice.dropFirst() {
print(anInt) // 4, 5, 6
}
As you can see, we are cycling through exactly the desired elements, with no reference to index numbers at all.
To iterate over the elements in the slice:
draggingFan?.forEach({ (element)
...
})
As far as I know, the get a specific element, it needs to be converted back to an array e.g.
let draggingFanArray = Array(draggingFan!)
Here's the playground code I used to toy around with various scenarios:
import Cocoa
var a: Array<Int>?
var b: ArraySlice<Int>?
a = [1, 2, 3, 4, 5, 6, 7]
b = a![3...5]
let count = b!.count
b!.forEach({ (element) in
print("\(element)")
})
let c = Array(b!)
print(c[2])
edit ArraySlice extension though:
extension ArraySlice {
func elementAtIndex(index: Int)->AnyObject?{
return Array(self)[index] as? AnyObject
}
}
If I have an array:
var arr = [1, 2, 3, 4, 5, 6, 7] // [1, 2, 3, 4, 5, 6, 7]
And I take a slice of the array:
let slice = arr[3..<arr.count] // [4, 5, 6, 7]
This slice will have a startIndex of 3, which means that indexing starts at 3 and ends at 6.
Now if I want a slice containing everything but the first element, I can use the dropFirst() method:
let sliceMinusFirst = slice.dropFirst() // [5, 6, 7]
And at this point, sliceMinusFirst has a startIndex of 4, which means my indexes range from 4 to 6.
Now if I wish to iterate over these to do something with the items, I can do the following:
for item in sliceMinusFirst {
print(item)
}
Alternatively, I can do it with forEach:
sliceMinusFirst.forEach { item in
print(item)
}
By using these forms of iteration, the fact that the startIndex is nonzero doesn't even matter, because I don't use the indices directly. And it also doesn't matter that, after taking a slice, I wanted to drop the first item. I was able to do that easily. I could have even done that at the time I wanted to do the iteration:
slice.dropFirst().forEach { item in
print(item)
}
Here I dropped the first item from the original slice, without creating any intermediate variables.
Remember that if you need to actually use the index, you're probably doing something wrong. And if you genuinely do need the index, make sure you understand what's going on.
Also if you want to get back to zero-based indexing once you make a slice, you can create an array from your slice:
let sliceArray = Array(slice) // [4, 5, 6, 7]
sliceArray.startIndex // 0

Resources