Flatten 2D list with indices - arrays

I am looking for an idiomatic method in Kotlin (JVM) to flatten a 2-dimensional list. But, unlike the existing .flatten(), I would like to retain the individual indices, similar to .withIndex(), but 2-dimensional.
Example:
// Before
[
["a", "b", "c"],
["d", "e"],
["f", "g", "h", "i"]
]
// Afterwards, something like
[
(0, 0, "a"), (0, 1, "b"), (0, 2, "c"),
(1, 0, "d"), (1, 1, "e"),
(2, 0, "f"), (2, 1, "g"), (2, 2, "h"), (2, 3, "i")
]

flattenWithIndex
Unsure whether there is an idiomatic approach to this already somewhere in the lib, but it is fairly easy to write this yourself with a bunch of nested .withIndex() and some (flat)-mapping:
// inspired by IndexedValue for 1D
data class GridValue<out T>(val rowIndex: Int, val colIndex: Int, val value: T)
// similar to flatten().withIndex() for 1D
fun <T> Iterable<Iterable<T>>.flattenWithIndex(): List<GridValue<T>> =
withIndex().flatMap { (rowIndex, row) ->
row.withIndex().map { (colIndex, value) ->
GridValue(rowIndex, colIndex, value)
}
}
withGridIndex
As a little bonus, here is the 2D variant of withIndex():
// only difference is map vs flatMap
fun <T> Iterable<Iterable<T>>.withGridIndex(): List<List<GridValue<T>>> =
withIndex().map { (rowIndex, row) ->
row.withIndex().map { (colIndex, value) ->
GridValue(rowIndex, colIndex, value)
}
}
Notes
As usual, substitute with sequences if necessary.
Technically, flattenWithIndex() could also be rewritten as
fun <T> Iterable<Iterable<T>>.flattenWithIndex(): List<GridValue<T>> =
withGridIndex().flatten()
But that would create unecessary lists in the process.

As you describe question is actually do type conversion like: List<List<String>> to List<Triple<Int, Int, String>>
Generalization: List<List<T>> to List<Triple<Int, Int, T>>
and code is:
fun <T> List<List<T>>.flattenWithIndex(): List<Triple<Int, Int, T>> {
val result = mutableListOf<Triple<Int, Int, T>>()
forEachIndexed { i, tList ->
tList.forEachIndexed { j, t ->
result.add(Triple(i, j, t))
}
}
return result
}
val list = listOf(listOf("a", "b", "c"), listOf("d", "e"), listOf("f", "g", "h", "i"))
println(list.flattenWithIndex())// [(0, 0, a), (0, 1, b), (0, 2, c), (1, 0, d), (1, 1, e), (2, 0, f), (2, 1, g), (2, 2, h), (2, 3, i)]

Related

Kotlin - index of duplicate elements in an array

Is there an easy way to get the index of matching elements in an array without writing a for loop and then collecting the index?
Eg: val arr = arrayOf<Int>(2,3,4,2,5,2,6,3,2)
Output: For element 2, output should be (0,3,5,8) and For element 3, output should be (1,7)
Kotlin provides indexOf(element) which returns first index and then lastIndexOf(element) which will give me last index. Am looking for an easy way to get indexes of all matching elements.
My solution: Standard solution of iterating over the array and collecting index.
var indexArrOf2 = mutableListOf<Int>()
var indexArrOf3 = mutableListOf<Int>()
for(i in arr.indices) {
if (arr[i] == 2) {
indexArrOf2.add(i)
}
if (arr[i] == 3) {
indexArrOf3.add(i)
}
}
Yes, you can use mapIndexedNotNull:
arr.mapIndexedNotNull { index, elem -> if (elem == 2) index else null }
A little convoluted but returns a map Map<Element, List<Indices>> to use as desired.
arr.mapIndexed { index, i -> i to index } //List<Pair<Int, Int>> - [(2, 0), (3, 1), (4, 2), (2, 3), (5, 4), (2, 5), (6, 6), (3, 7), (2, 8)]
.groupBy { it.first } //Map<Int, List<Pair<Int, Int>>> - {2=[(2, 0), (2, 3), (2, 5), (2, 8)], 3=[(3, 1), (3, 7)], 4=[(4, 2)], 5=[(5, 4)], 6=[(6, 6)]}
.mapValues { it.value.map { it.second } } //Map<Int, List<Int>> - {2=[0, 3, 5, 8], 3=[1, 7], 4=[2], 5=[4], 6=[6]}
I'd use the withIndex() extension function to add the index.  You can then select the matching items, and get their indices:
val arr = arrayOf(2, 3, 4, 2, 5, 2, 6, 3, 2)
println(arr.withIndex().filter{ it.value == 2 }.map{ it.index })
// prints '[0, 3, 5, 8]'

Pairing last element from previous pair as first in next pair [duplicate]

Given I've got an array in Swift such as [1,2,3,4], a method pairs() will transform it in to the array of tuples: [(1,2), (2,3), (3,4)].
Here are some more examples of how pairs() should behave:
pairs([]) should return [] as it has no pairs.
pairs([1]) should also return [], as it has no pairs.
pairs([1,2]) should be [(1,2)]. It has just one pair.
I can write code to do this for Array, but I'd like to have pairs() available as an extension on Sequence, so that it returns a Sequence of the pairs. This would make it useable on any sequence, and compatible with methods such as map, reduce, filter, etc.
How do I go about creating a Sequence like this? And how do I write the method to transform any Sequence in this way so that it can be used as flexibly as possible?
We can use zip() and dropFirst() if we define an extension
on the Collection type:
extension Collection {
func pairs() -> AnySequence<(Element, Element)> {
return AnySequence(zip(self, self.dropFirst()))
}
}
Example:
let array = [1, 2, 3, 4]
for p in array.pairs() {
print(p)
}
Output:
(1, 2)
(2, 3)
(3, 4)
More examples:
print(Array("abc".pairs()))
// [("a", "b"), ("b", "c")]
print([1, 2, 3, 4, 5].pairs().map(+))
// [3, 5, 7, 9]
print([3, 1, 4, 1, 5, 9, 2].pairs().filter(<))
// [(1, 4), (1, 5), (5, 9)]
(Unlike I wrote in the first version of this answer ...) this
approach is not safe when applied to a Sequence, because it is
not guaranteed that a sequence can be traversed multiple times
non-destructively.
Here is a direct implementation with a custom iterator type
which works on sequences as well:
struct PairSequence<S: Sequence>: IteratorProtocol, Sequence {
var it: S.Iterator
var last: S.Element?
init(seq: S) {
it = seq.makeIterator()
last = it.next()
}
mutating func next() -> (S.Element, S.Element)? {
guard let a = last, let b = it.next() else { return nil }
last = b
return (a, b)
}
}
extension Sequence {
func pairs() -> PairSequence<Self> {
return PairSequence(seq: self)
}
}
Example:
print(Array([1, 2, 3, 4].pairs().pairs()))
// [((1, 2), (2, 3)), ((2, 3), (3, 4))]

Sort 2 linked arrays in Swift? [duplicate]

This question already has answers here:
In Swift how can I sort one array based on another array?
(4 answers)
Closed 4 years ago.
I want to sort one array and "mirror" order changes to another array of the same dimension.
The question is similar to this one but for Swift language:
Better way to sort 2 "linked" arrays?
Example:
let arr1 = ["a", "b", "c", "d", "e"]
let arr2 = [1, 5, 9, 2, 3]
... //sort
//result == ["a", "d", "e", "b", c"]
Approximate solution I know:
for i in stride(from 0, to: arr2.count - 1, by: 1) {
for j in stride(from i + 1, to: arr2.count, by: 1) {
if arr2[i] > arr2[j] {
...//swap arr2[i] and arr2[j]
...//swap arr1[i] and arr1[j]
}
}
}
But they added a lot of additional possibilities for advanced working with arrays in Swift. So is it possible to simplify this solution with inner Swift features?
Note: arr1 and arr2 are given as separate arrays.
EDITED
Yes. You found the similar questions but their titles are awful and don't reflect the answers their authors need. In other words if you delete/close my question the people may continue to ask it again because it is impossible to find something with existing titles!
zip the arrays together
sort the new array by array 2
map the array to array 1
let arr1 = ["a", "b", "c", "d", "e"]
let arr2 = [1, 5, 9, 2, 3]
let result = zip(arr1, arr2) // [("a", 1), ("b", 5), ("c", 9), ("d", 2), ("e", 3)]
.sorted(by: {$0.1 < $1.1}) // [("a", 1), ("d", 2), ("e", 3), ("b", 5), ("c", 9)]
.map{ $0.0 } // ["a", "d", "e", "b", "c"]

Map Swift array with specific format

Given an array that contains elements like this:
let array = [[a], [b, c], [d, e, f]]
Is there an elegant way to convert this array to an array which returns a tuple with the index of the outer array:
let result = [(a, 0), (b, 1), (c, 1), (d, 2), (e, 2), (f, 2)]
let array = [["a"], ["b", "c"], ["d", "e", "f"]]
let result = zip(array, array.indices).flatMap { subarray, index in
subarray.map { ($0, index) }
}
result is:
[("a", 0), ("b", 1), ("c", 1), ("d", 2), ("e", 2), ("f", 2)]
I used zip(array, array.indices) instead of array.enumerated() because you specifically asked for a tuple with the array index — enumerated() produces tuples with zero-based integer offsets. If your source collection is an array, it doesn't make a difference, but other collections (like ArraySlice) would behave differently.

Type-safe rectangular multidimensional array type

How do you represent a rectangular 2-dimensional (or multidimensional) array data structure in Scala?
That is, each row has the same length, verified at compile time, but the dimensions are determined at runtime?
Seq[Seq[A]] has the desired interface, but it permits the user to provide a "ragged" array, which can result in a run-time failure.
Seq[(A, A, A, A, A, A)] (and similar) does verify that the lengths are the same, but it also forces this length to be specified at compile time.
Example interface
Here's an example interface of what I mean (of course, the inner dimension doesn't have to be tuples; it could be specified as lists or some other type):
// Function that takes a rectangular array
def processArray(arr : RectArray2D[Int]) = {
// do something that assumes all rows of RectArray are the same length
}
// Calling the function (OK)
println(processArray(RectArray2D(
( 0, 1, 2, 3),
(10, 11, 12, 13),
(20, 21, 22, 23)
)))
// Compile-time error
println(processArray(RectArray2D(
( 0, 1, 2, 3),
(10, 11, 12),
(20, 21, 22, 23, 24)
)))
This is possible using the Shapeless library's sized types:
import shapeless._
def foo[A, N <: Nat](rect: Seq[Sized[Seq[A], N]]) = rect
val a = Seq(Sized(1, 2, 3), Sized(4, 5, 6))
val b = Seq(Sized(1, 2, 3), Sized(4, 5))
Now foo(a) compiles, but foo(b) doesn't.
This allows us to write something very close to your desired interface:
case class RectArray2D[A, N <: Nat](rows: Sized[Seq[A], N]*)
def processArray(arr: RectArray2D[Int, _]) = {
// Run-time confirmation of what we've verified at compile-time.
require(arr.rows.map(_.size).distinct.size == 1)
// Do something.
}
// Compiles and runs.
processArray(RectArray2D(
Sized( 0, 1, 2, 3),
Sized(10, 11, 12, 13),
Sized(20, 21, 22, 23)
))
// Doesn't compile.
processArray(RectArray2D(
Sized( 0, 1, 2, 3),
Sized(10, 11, 12),
Sized(20, 21, 22, 23)
))
Using encapsulation to ensure proper size.
final class Matrix[T]( cols: Int, rows: Int ) {
private val container: Array[Array[T]] = Array.ofDim[T]( cols, rows )
def get( col: Int, row: Int ) = container(col)(row)
def set( col: Int, row: Int )( value: T ) { container(col)(row) = value }
}
Note: I misread the question, mistaking a rectangle for a square. Oh, well, if you're looking for squares, this would fit. Otherwise, you should go with #Travis Brown's answer.
This solution may not be the most generic one, but it coincides with the way Tuple classes are defined in Scala.
class Rect[T] private (val data: Seq[T])
object Rect {
def apply[T](a1: (T, T), a2: (T, T)) = new Rect(Seq(a1, a2))
def apply[T](a1: (T, T, T), a2: (T, T, T), a3: (T, T, T)) = new Rect(Seq(a1, a2, a3))
// Continued...
}
Rect(
(1, 2, 3),
(3, 4, 5),
(5, 6, 7))
This is the interface you were looking for and the compiler will stop you if you have invalid-sized rows, columns or type of element.

Resources