Say I have a List<Tuple>, where the first element in each is a string. Is there an extension function in Kotlin to select the first element from each of these tuples?
I'm looking for something like the C# LINQ syntax for Select:
myTuples.Select(t => t.item1)
In Kotlin, a Tuple could be a Pair or a Triple. You could just map over the list and select out the first element, like this:
val myTuples : List<Triple<String,String,String>> = listOf(
Triple("A", "B", "C"),
Triple("D", "E", "F")
)
val myFirstElements: List<String> = myTuples.map { it.first } // ["A", "D"]
And of course, you can leave off the types, I've left them in to make this easier to follow.
Related
So I have a struct and a dictionary that look like this:
struct minStruct {
var labelText:String?
var descText:String?
var imaginator:UIImage?
var rea:String?
var url:NSURL?}
var dict = [String:[minStruct]]()
Thus, I have a dictionary with the value as an array of structs. In my application I create an array of all the structs inside the dictionary to be able to show the structs in a tableView, which is done by this code:
let dictValues = Array(dict.values)
let dictFlat = Array(dictValues.flatten())
The new array dictFlat is used for populating the tableView, as it contains every struct that was contained inside of the original dictionary. If I would like to remove a struct from the tableView, i would of course remove it from the array dictFlat, however I need to remove the same struct from the original dictionary (dict) to achieve what I want. So my question is simply how to remove the same struct that is deleted from the array dictFlat from the dictionary dict. To clarify, you could you this example:
dict = ["Food":[minStruct(labelText: "this is a string", descText: "Also a string", imaginator: UIImage(named: "image-name")!, rea: "also a string", url: NSURL(string: "https://www.google.com")]]
Now dictFlat will contain the struct displayed inside of dict above, and now I want to delete that struct from both. Using swipe to delete from the tableView, the only struct that will be deleted is the one inside of dictFlat (using the indexPath to delete just as you would usually do when deleting from a tableView). Now I want to delete the same item which was deleted from dictFlat and also from the tableView, from the original dictionary (dict). So what I want is to check if dict contains the struct that was deleted from dictFlat, and if it does contain it, it shall be deleted.
I hope that I was clear enough, thanks in advance!
What is the trouble? See the example, I used there [Int] as a value, but it could be anything else
var dict:[String:[Int]] = [:]
let arr0 = [1,2,3,4,5]
let arr1 = [2,3,4,5,6]
dict["arr0"] = arr0
dict["arr1"] = arr1
// working copy
var arr = dict["arr0"] ?? []
// remove one value
arr.removeAtIndex(2)
// update your dictionary
dict["arr0"] = arr
print(dict) // ["arr1": [2, 3, 4, 5, 6], "arr0": [1, 2, 4, 5]]
In Java we could do the following
public class TempClass {
List<Integer> myList = null;
void doSomething() {
myList = new ArrayList<>();
myList.add(10);
myList.remove(10);
}
}
But if we rewrite it to Kotlin directly as below
class TempClass {
var myList: List<Int>? = null
fun doSomething() {
myList = ArrayList<Int>()
myList!!.add(10)
myList!!.remove(10)
}
}
I got the error of not finding add and remove function from my List
I work around casting it to ArrayList, but that is odd needing to cast it, while in Java casting is not required. And that defeats the purpose of having the abstract class List
class TempClass {
var myList: List<Int>? = null
fun doSomething() {
myList = ArrayList<Int>()
(myList!! as ArrayList).add(10)
(myList!! as ArrayList).remove(10)
}
}
Is there a way for me to use List but not needing to cast it, like what could be done in Java?
Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets, maps, etc). Precise control over exactly when collections can be edited is useful for eliminating bugs, and for designing good APIs.
https://kotlinlang.org/docs/reference/collections.html
You'll need to use a MutableList list.
class TempClass {
var myList: MutableList<Int> = mutableListOf<Int>()
fun doSomething() {
// myList = ArrayList<Int>() // initializer is redundant
myList.add(10)
myList.remove(10)
}
}
MutableList<Int> = arrayListOf() should also work.
Defining a List collection in Kotlin in different ways:
Immutable variable with immutable (read only) list:
val users: List<User> = listOf( User("Tom", 32), User("John", 64) )
Immutable variable with mutable list:
val users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
or without initial value - empty list and without explicit variable type:
val users = mutableListOf<User>()
//or
val users = ArrayList<User>()
you can add items to list:
users.add(anohterUser) or
users += anotherUser (under the hood it's users.add(anohterUser))
Mutable variable with immutable list:
var users: List<User> = listOf( User("Tom", 32), User("John", 64) )
or without initial value - empty list and without explicit variable type:
var users = emptyList<User>()
NOTE: you can add* items to list:
users += anotherUser - *it creates new ArrayList and assigns it to users
Mutable variable with mutable list:
var users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
or without initial value - empty list and without explicit variable type:
var users = emptyList<User>().toMutableList()
//or
var users = ArrayList<User>()
NOTE: you can add items to list:
users.add(anohterUser)
but not using users += anotherUser
Error: Kotlin: Assignment operators ambiguity:
public operator fun Collection.plus(element: String): List defined in kotlin.collections
#InlineOnly public inline operator fun MutableCollection.plusAssign(element: String): Unit defined in kotlin.collections
see also:
https://kotlinlang.org/docs/reference/collections.html
Agree with all above answers of using MutableList but you can also add/remove from List and get a new list as below.
val newListWithElement = existingList + listOf(element)
val newListMinusElement = existingList - listOf(element)
Or
val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
Apparently, the default List of Kotlin is immutable.
To have a List that could change, one should use MutableList as below
class TempClass {
var myList: MutableList<Int>? = null
fun doSomething() {
myList = ArrayList<Int>()
myList!!.add(10)
myList!!.remove(10)
}
}
Updated
Nonetheless, it is not recommended to use MutableList unless for a list that you really want to change. Refers to https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 for how Read-only collection provides better coding.
In Kotlin you must use MutableList or ArrayList.
Let's see how the methods of MutableList work:
var listNumbers: MutableList<Int> = mutableListOf(10, 15, 20)
// Result: 10, 15, 20
listNumbers.add(1000)
// Result: 10, 15, 20, 1000
listNumbers.add(1, 250)
// Result: 10, 250, 15, 20, 1000
listNumbers.removeAt(0)
// Result: 250, 15, 20, 1000
listNumbers.remove(20)
// Result: 250, 15, 1000
for (i in listNumbers) {
println(i)
}
Let's see how the methods of ArrayList work:
var arrayNumbers: ArrayList<Int> = arrayListOf(1, 2, 3, 4, 5)
// Result: 1, 2, 3, 4, 5
arrayNumbers.add(20)
// Result: 1, 2, 3, 4, 5, 20
arrayNumbers.remove(1)
// Result: 2, 3, 4, 5, 20
arrayNumbers.clear()
// Result: Empty
for (j in arrayNumbers) {
println(j)
}
UPDATE: As of Kotlin 1.3.70, the exact buildList function below is available in the standard library as an experimental function, along with its analogues buildSet and buildMap. See https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/.
Confining Mutability to Builders
The top answers here correctly speak to the difference in Kotlin between read-only List (NOTE: it's read-only, not "immutable"), and MutableList.
In general, one should strive to use read-only lists, however, mutability is still often useful at construction time, especially when dealing with third-party libraries with non-functional interfaces. For cases in which alternate construction techniques are not available, such as using listOf directly, or applying a functional construct like fold or reduce, a simple "builder function" construct like the following nicely produces a read-only list from a temporary mutable one:
val readonlyList = mutableListOf<...>().apply {
// manipulate your list here using whatever logic you need
// the `apply` function sets `this` to the `MutableList`
add(foo1)
addAll(foos)
// etc.
}.toList()
and this can be nicely encapsulated into a re-usable inline utility function:
inline fun <T> buildList(block: MutableList<T>.() -> Unit) =
mutableListOf<T>().apply(block).toList()
which can be called like this:
val readonlyList = buildList<String> {
add("foo")
add("bar")
}
Now, all of the mutability is isolated to one block scope used for construction of the read-only list, and the rest of your code uses the read-only list that is output from the builder.
You can do with create new one like this.
var list1 = ArrayList<Int>()
var list2 = list1.toMutableList()
list2.add(item)
Now you can use list2, Thank you.
https://kotlinlang.org/docs/reference/collections.html
According to above link List<E> is immutable in Kotlin.
However this would work:
var list2 = ArrayList<String>()
list2.removeAt(1)
A list is immutable by Default, you can use ArrayList instead. like this :
val orders = arrayListOf<String>()
then you can add/delete items from this like below:
orders.add("Item 1")
orders.add("Item 2")
by default ArrayList is mutable so you can perform the operations on it.
In concept of immutable data, maybe this is a better way:
class TempClass {
val list: List<Int> by lazy {
listOf<Int>()
}
fun doSomething() {
list += 10
list -= 10
}
}
I am using Gremlin-Scala and I have the following code:
val paths = w.as("a").out("next").jump(
to = "a",
jumpPredicate = { t: Traverser[Vertex] =>
t.loops < 5
}
).path.toList
I don't know when my loop will finish, so I have no access to the size and if I put wrong number for x in t.loops > x then I will have problem. I changed my code in following and it works well. it has two problems (1- it's ugly 2- I have to call get() which I think is not efficient)
Is there better way to do this?
val paths = w.as("a").out("next").jump(
to = "a",
jumpPredicate = { t: Traverser[Vertex] =>
t.get().out("next").size > 0
}
).path.toList
Re your problems:
1: it's ugly - what exactly do you dislike about it? You could leave out the type annotation and variable names...
2: there's nothing inefficient about .get there - it's a simple getter on the traverser to get the element. jump gives you the traverser instead of the element so that you have more context - the traverser e.g. holds information about how many loops you've done so far, the path, etc.
This should work:
val paths = w.as("a").out("next").jump(
"a",
_.get().out("next").size > 0
).path.toList
Another loop example (finding the shortest path):
http://www.michaelpollmeier.com/2014/12/27/gremlin-scala-shortest-path/
var dict = ["alpha": ["a", "b", "c", "d"]]
// output : ["alpha": ["a", "b", "c", "d"]]
var alphaList = dict["alpha"]
// output : {["a", "b", "c", "d"]
alphaList?.removeAtIndex(1)
// output : {Some "b"}
alphaList
// output : {["a", "c", "d"]}
dict
// output : ["alpha": ["a", "b", "c", "d"]]
Why is 'dict' not altered? Is it because 'alphaList' is a copy of the array and not the actual array inside the dictionary? Can anyone point me where in Swift language documentation I can find this information?
What is the correct/functional way to manipulate values (of complex type) of a dictionary?
Good question yes it creates the copy of the value in your case the value is Array
var alphaList = dict["alpha"]
/* which is the copy of original array
changing it will change the local array alphaList as you can see by your output */
output : {Some "b"}
In order to get the original array directly use
dict["alpha"]?.removeAtIndex(1)
Or update it using the key
alphaList?.removeAtIndex(1)
dict["alpha"] = alphaList
Apple : Assignment and Copy Behavior for Strings, Arrays, and Dictionaries
Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.
This behavior is different from NSString, NSArray, and NSDictionary in Foundation, which are implemented as classes, not structures. NSString, NSArray, and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. "
Swift arrays and dictionaries are value (struct) times. There are only one reference to such instance. While NSArray and NSDictonary are class type and there could be multiple references to such instances.
The statement var alphaList = dict["alpha"] makes copy for ["a", "b", "c", "d"], so you cannot change the original array.
If you want to mutate original "alpha" you have to use dict as root variable:
dict["alpha"]?.removeAtIndex(1)
You are right, alphaList is a copy, hence any change you make on it is local and does not affect the original array. The documentation describes that in Structures and Enumerations Are Value Types.
The only way to make changes to an array after extracting it from somewhere else is by passing the array to a function by reference, using the inout parameter modifier:
func modifyAlphaList(inout alphaList: [String]?) {
alphaList?.removeAtIndex(1)
}
modifyAlphaList(&dict["alpha"])
dict // (.0 "alpha", ["a", "c", "d"])
This link should help
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_150
Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.
I'm trying to insert new key-value pair in dictionary, which nested in another one Dictionary:
var dict = Dictionary<Int, Dictionary<Int, String>>()
dict.updateValue([1 : "one", 2: "two"], forKey: 1)
dict[1]?[1] // {Some "one"}
if var insideDic = dict[1] {
// it is a copy, so I can't insert pair this way:
insideDic[3] = "three"
}
dict // still [1: [1: "one", 2: "two"]]
dict[1]?[3] = "three" // Cannot assign to the result of this expression
dict[1]?.updateValue("three", forKey: 3) // Could not find a member "updateValue"
I believe should be a simple way to handle it, but I spent an hour and still can't figure it out.
I can use NSDictionary instead, but I really like to understand how I should manage nested Dictionaries in Swift?
Dictionarys are value types so are copied on assignment. As a result you are going to have to get the inner dictionary (which will be a copy), add the new key, then re-assign.
// get the nested dictionary (which will be a copy)
var inner:Dictionary<Int, String> = dict[1]!
// add the new value
inner[3] = "three"
// update the outer dictionary
dict[1] = inner
println(dict) // [1: [1: one, 2: two, 3: three]]
You could use one of the new utility libraries such as ExSwift to make this a bit simpler:
dict[1] = dict[1]!.union([3:"three"])
This uses the union method that combines two dictionaries.