I'm trying to get used to the idioms and shortcuts in Kotlin and I'm wondering if there was any way to do this.
val pairList = listOf(Pair(1, 2), Pair(5, 10), Pair(12, 15))
val firstList = // should be [1, 5, 12]
Or in general, any class with any one of their member variables. I currently have:
val pairList = listOf(Pair(1, 2), Pair(5, 10), Pair(12, 15))
val firstList = ArrayList<Int>()
pairList.forEach { firstList.add(it.first) }
It is: val firstList = pairList.map { it.first }
first represents the 1st member of the pair, and of course there is second for the 2nd member
The same firstList be generalized for:
val pairList = listOf(Pair(ClassA(), ClassB()), Pair(ClassA(), ClassB()), Pair(ClassA(), ClassB()))
Related
what's the idiomatic way to take a list and group it into tuples of size n?
eg: group into 3's with triple
val list = listOf(1,2,3,4)
val partitioned = list.groupsOf(3)
// partitioned[0] = List<Int> 1, 2, 3
// partitioned[1] = List<Int> 4
but preferably something like this
val list = listOf(1,2,3,4)
val newList = mutableListOf()
list.forGroupsOf(3) { triple: Triple<Int?> ->
newList.add( triple )
}
// partitioned[0] = Triple<Int?> 1, 2, 3
// partitioned[1] = Triple<Int?> 4, null, null
NOTE: List.groupsOf and List.forGroupsOf I made up for this example
Kotlin provides a function called chunked(n) which produces a list of lists with n elements each:
val list = listOf(1, 2, 3, 4)
val tuples = list.chunked(2).map { Tuple(it[0], it[1]) }
Or alternatively:
val list = listOf(1, 2, 3, 4)
val tuples = list.chunked(2) { Tuple(it[0], it[1]) }
Keep in mind that this produces lists with max n elements.
I am searching for Kotlin alternative to:
(cons 1 '(2 3)) in lisp or
1 : [2, 3] in haskell or
1 :: List(2, 3) in scala,
(which all result in sth like [1, 2, 3])
so I can prepend an element to a List<T> (or any other list you can offer).
It will also be fine if one could provide O(1) head and tail Kotlin alternatives (I've found just first())
I think the easiest would be to write:
var list = listOf(2,3)
println(list) // [2, 3]
list = listOf(1) + list
println(list) // [1, 2, 3]
There is no specific tail implementation, but you can call .drop(1) to get the same. You can make this head\tail more generic by writing these extension properties:
val <T> List<T>.tail: List<T>
get() = drop(1)
val <T> List<T>.head: T
get() = first()
Then:
val list = listOf(1, 2, 3)
val head = list.head
val tail = list.tail
Some more info: Kotlin List tail function
Any class which implements Deque will suitable for you, for example LinkedList:
val linkedList = LinkedList(listOf(2, 3))
linkedList.push(1)
println(linkedList) // [1, 2, 3]
Creating lists throught constructor LinkedList(listOf(2, 3)) in many places can be annoying, so feel free to write factory method:
fun <T> linkedListOf(vararg elements: T): LinkedList<T> {
return LinkedList<T>(elements.toList())
}
// Usage:
val list = linkedListOf(2, 3)
list.push(1)
println(list) // [1, 2, 3]
Simple, just wrap the element to prepend in a List and then use the + operator (or List.plus()) to concatenate the two Lists:
val list1 = listOf(2, 3) // [2, 3]
val list2 = listOf(1) + list1 // [1, 2, 3]
For your second question, in Kotlin 1.2 there are:
List.first()
List.last()
Both are O(1)
This could be done easily with extension functions as below
Prepending element
fun <T> MutableList<T>.prepend(element: T) {
add(0, element)
}
Prepending list
fun <T> MutableList<T>.prependAll(elements: List<T>) {
addAll(0, elements)
}
Inserts an element into the list at the specified index.
abstract fun add(index: Int, element: E)
Thus answer is
list.add(0,element)
If you do that often in your code for some reason, consider adding an extension operator method such as:
operator fun <T> T.plus(tail: List<T>): List<T> {
val list = ArrayList<T>(1 + tail.size)
list.add(this)
list.addAll(tail)
return list
}
Then your code could work Scala-like: 1 + listOf(2, 3)
Another way to achieve the same behaviour, shorter but sacrifices some memory:
operator fun <T> T.plus(tail: List<T>): List<T> {
return mutableListOf(this).apply {
addAll(tail)
}
}
To be as close to Lisp as possible consider using immutable linked list.
You can use pcollections
val list = ConsPStack.from(listOf(2, 3))
val newList = list + 1
println(list) // [2, 3]
println(newList) // [1, 2, 3]
Head:
list.first() // 1
list[0] // 1
(unfortunately this thing needs one allocation)
Tail:
list - 0 // [2, 3]
list.subList(1) // [2, 3]
Looks rather ugly.
Hopefully we'll get better API when kotlinx.collections.immutable will be ready. It's an effort to create standard Kotlin immutable collections (not just read-only ones that we currently have). As of now this project is still at very early stage (I was unable to find structure that supports efficient prepend/head/tail there)
I'm not entirely sure what you want to do, so please try one of the following.
Mutating list:
val list = mutableListOf(3, 2)
list.add(1)
Copping an immutable list:
var list = listOf(3, 2)
list = list + 1
Lets take an example where store is my class.
class store(val a:Int) { }
In the code i want to create a list of store.
val list : List[store] = new List[store]()
How can i add a store in the same list?
First off, it's usually a good idea to capitalize your class names.
scala> class Store(val a:Int) { }
defined class Store
scala> val list : List[Store] = List.empty
list: List[Store] = List()
scala> val newList = new Store(4) :: list
newList: List[Store] = List(Store#243306de)
Your list is, by default, immutable so you'll have a new list every time an element is added.
scala> val newerList = new Store(71) :: newList
newerList: List[Store] = List(Store#30f57af0, Store#243306de)
ADDENDUM
If you need a mutable list (not usually recommended) you could try the following.
scala> import scala.collection.mutable.MutableList
import scala.collection.mutable.MutableList
scala> val myList: MutableList[Store] = MutableList.empty
myList: scala.collection.mutable.MutableList[Store] = MutableList()
scala> myList += new Store(56)
res322: myList.type = MutableList(Store#6421614e)
scala> myList += new Store(29)
res323: myList.type = MutableList(Store#6421614e, Store#85b26)
scala> myList += new Store(11)
res324: myList.type = MutableList(Store#6421614e, Store#85b26, Store#5d2f7883)
Mutable variables are considered poor style and an impediment to proper Functional Programming.
To add element to the beginning of the list use :: :
val l = List(1, 2, 3)
val l1 = 5 :: l // List(5, 1, 2, 3)
or
val l1 = l.::(5)
To add element to the end of the list use :+ :
val l2 = l :+ 5 // List(1, 2, 3, 5)
So, to add store object to the end of the list (though it is not efficient), write this:
val s = new Store(1)
val newList = list :+ s // list is immutable
I have a List
val family=List("1","2","11","12","21","22","31","33","41","44","51","55")
i want to take its first n elements but the problem is that parents size is not fixed.
val familliar=List("1","2","11") //n=3
You can use take
scala> val list = List(1,2,3,4,5,6,7,8,9)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> list.take(3)
res0: List[Int] = List(1, 2, 3)
List(1,2,3).take(100) //List(1,2,3)
The signature of take will compare the argument with index, so the incremental index will never more than argument
The signature of take
override def take(n: Int): List[A] = {
val b = new ListBuffer[A]
var i = 0
var these = this
while (!these.isEmpty && i < n) {
i += 1
b += these.head
these = these.tail
}
if (these.isEmpty) this
else b.toList
}
Use take:
val familliar = family.take(3)
I'm would like to create generic (invariant) method in Scala which copies elements from source list to destination list. In Java there is copy method in java.util.Collections (see http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#copy%28java.util.List,%20java.util.List%29). I know in Scala List is immutable object so i would like to create and return new list.
I've written the following code:
def copy[T](dest:List[T], src:List[T]):List[T] = {
if(dest.length<src.length) throw new Exception("IndexOutOfBoundsException")
else if(src==Nil) dest
else {
var ret = dest
ret = dest.updated(0, src.first)
var i=1
val f:(T=>Unit) = a => {
if(i<src.length) ret=ret.updated(i, src(i))
i+=1
()
}
dest.foreach(f)
ret
}
}
But I think it could be written better. Could you help me to write better code? Thanks in advance.
EDITED: Maybe I expressed unclear what I want to do. I have two lists (scala.collection.immutable.List), e.g. src (length=x) and dest(length=y>=x). I would like to replace first x elements of dest list with elements from src list.
Do you mean scala.collection.immutable.List? It is immutable. No need to copy them. Immutable means that nothing can change it, so you can use it in different threads.
Generic way of creating collections in scala is builder. You can get one from CanBuildFrom object. Alternatively you can get it from genericBuilder method of collection instance.
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> val b = list.genericBuilder[Int]
b: scala.collection.mutable.Builder[Int,List[Int]] = ListBuffer()
scala> list.foreach{ b += _ }
scala> val result = b.result // this code is useless. `val result = list` is enough
result: List[Int] = List(1, 2, 3)
If you want to create new collection of different type based on existing collection, you can use collection.breakOut methid like this:
scala> val list = List('a', 'b', 'c')
list: List[Char] = List(a, b, c)
scala> val result: String = list.map{identity}(collection.breakOut)
result: String = abc
Upd
require(src.length <= dest.length, "IndexOutOfBoundsException")
src ++ dest.drop(src.length)
If you want to get an updated list you can use map on your list. Map works by applying a function to each element in the list, and returning updated list.
http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/
You are thinking far too procedurally, say what you want not how to do it...
how about:
val src = List(1,2,3)
val dest = src map {x => x}
if you really want to make a function of it
def copy[T](src: List[T]): List[T] = src map {x => x}
in response to OP's update:(which has also been proposed by others)
def copy[T](src: List[T], dest: List[T]): List[T] = src ++ dest.drop(src.length)
You could use:
if(dest.length <= src.length) dest ::: src.drop(dest.length)
else dest.dropRight(dest.length - src.length) //or throw exception...
Maybe you want something like
def copy[T](dest: Seq[T], src: Seq[T]): Seq[T] = {
require(dest.length >= src.length)
src ++ (dest drop src.length)
}
I generalized to Seqs, but it works on Lists, of course
The require method throws IllegalArgumentException if not fulfilled at runtime
Then you need only append the last (y-x) elements of the destination list to to the source list (where x = src.length; y = dest.length)
You do this by dropping x elements from dest and appending the remaining to src.
This is what you get from the REPL
scala> val src = List(1, 2, 3, 4)
src: List[Int] = List(1, 2, 3, 4)
scala> val dst = List(10, 20)
dst: List[Int] = List(10, 20)
scala> val dst2 = List(10, 20, 30, 40, 50, 60)
dst2: List[Int] = List(10, 20, 30, 40, 50, 60)
scala> copy(dst, src)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:221)
at .copy(<console>:8)
at .<init>(<console>:11)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
<...>
scala> copy(dst2, src)
res1: Seq[Int] = List(1, 2, 3, 4, 50, 60)