Why do we have functions that named componentN in Kotlin - arrays

I've just looked at Kotlin standard library and found some strange extension-functions called componentN where N is index from 1 to 5.
There are functions for all types of primitives. For example:
/**
* Returns 1st *element* from the collection.
*/
#kotlin.internal.InlineOnly
public inline operator fun IntArray.component1(): Int {
return get(0)
}
It looks curiously for me. I'm interested in developers motives. Is it better to call array.component1() instead of array[0] ?

Kotlin has many functions enabling particular features by convention. You can identify those by the use of the operator keyword. Examples are delegates, operator overload, index operator and also destructuring declarations.
The functions componentX allow destructuring to be used on a particular class. You have to provide these functions in order to be able to destructure instances of that class into its components. It’s good to know that data classes provide these for each of there properties by default.
Take a data class Person:
data class Person(val name: String, val age: Int)
It will provide a componentX function for each property so that you can destructure it like here:
val p = Person("Paul", 43)
println("First component: ${p.component1()} and second component: ${p.component2()}")
val (n,a) = p
println("Descructured: $n and $a")
//First component: Paul and second component: 43
//Descructured: Paul and 43
Also see this answer I gave in another thread:
https://stackoverflow.com/a/46207340/8073652

These are Destructuring Declarations and they're very convenient in certain cases.
val arr = arrayOf(1, 2, 3)
val (a1, a2, a3) = arr
print("$a1 $a2 $a3") // >> 1 2 3
val (a1, a2, a3) = arr
is compiled down to
val a1 = arr.component1()
val a2 = arr.component2()
val a3 = arr.component3()

Related

Accessing array inside composite type in Julia

I have the following two structs. When I initialize the struct with a constructor, an array is created, but it is not what I expected.
using Distributions
mutable struct XYZ
x::Float64
y::Float64
z::Float64
end
mutable struct Coords
r::Vector{XYZ}
end
""" Make a structure called test that contains a vector of type XYZ
I want to have 10 XYZ structs in the "r" Vector """
Coords() = ( rand(Uniform(0,1.0),10,3) )
test = Coords()
I want to access test by going test.r.x[i], however Julia complains that type Tuple has no field r. What it does create is a 2 dimensional array of size 10x3 and I can call elements via test[i,j] but this is far from what I want. I want to have other arrays/variables in the composite with callable names...
I tried initializing this way as well
XYZ() = (rand(),rand(),rand())
Coords() = ([ XYZ() for i in 1:10 ])
test = Coords()
I still get the same warning. It seems like I have created a tuple rather than a composite type. How do I create a composite type that has arrays/vectors inside of other structs?
I am using Julia version 1.0.2
Your are never actually calling the inner constructor in Coords(). To achieve what you want:
XYZ() = XYZ(rand(), rand(), rand())
Coords() = Coords([XYZ() for _ in 1:10])
But I would recommend against providing a constructor that initializes a special random layout. Instead, you could properly overload rand for XYZ, which gives you an array-rand for free:
julia> import Random
julia> Random.rand(rng::Random.AbstractRNG, ::Random.SamplerType{XYZ}) = XYZ(rand(rng), rand(rng), rand(rng))
julia> rand(XYZ)
XYZ(0.7580070440261963, 0.15662533181464178, 0.7450476071687568)
julia> rand(XYZ, 10)
10-element Array{XYZ,1}:
XYZ(0.5984858021544213, 0.16235318543392796, 0.729919026616209)
XYZ(0.45516751074248374, 0.9667694185826785, 0.39798147467761247)
XYZ(0.7329129925610325, 0.7725520616259764, 0.42264014343531)
XYZ(0.10415869248789567, 0.4193162272272648, 0.3265074454289505)
XYZ(0.2286383169588948, 0.7119393337105202, 0.5166340562764509)
XYZ(0.23011692279595186, 0.35344093654843767, 0.9488399720160021)
XYZ(0.20464532213275577, 0.05761320898130973, 0.7694525743407523)
XYZ(0.3022492318001946, 0.9212313012991236, 0.819167833632835)
XYZ(0.6331585756351794, 0.9812979781832118, 0.3969247687412505)
XYZ(0.6049257667248391, 0.7155977104637223, 0.5294492917395452)
julia> Coords(rand(XYZ, 10))
Coords(XYZ[XYZ(0.633945, 0.882152, 0.750866), XYZ(0.496134, 0.241877, 0.188791), XYZ(0.267383, 0.552298, 0.613393), XYZ(0.569428, 0.503757, 0.120985), XYZ(0.822557, 0.982106, 0.37321), XYZ(0.250684, 0.701853, 0.509496), XYZ(0.886511, 0.83301, 0.381657), XYZ(0.628089, 0.00574949, 0.730268), XYZ(0.382186, 0.411701, 0.86016), XYZ(0.904469, 0.854098, 0.270464)])

Vectorize an S4 class in R

I got some troubles defining array like classes in a way that they are fully typed (as far as that is possible in R).
My example: I want to define a class Avector, which should contain an arbitrary number of elements of the class A.
# Define the base class
setClass("A", representation(x = "numeric"))
# Some magic needed ????
setClass("Avector", ???)
# In the end one should be able to use it as follows:
a1 <- new("A", x = 1)
a2 <- new("A", x = 2)
X <- new("Avector", c(a1, a2))
I am aware that having a vector of objects is not possible in R. So I guess it will be stored in a kind of "typed" list.
I have found some solution, but I am not happy with it:
# Define the vectorized class
setClass(
"Avector",
representation(X = "list"),
valididty = function(.Object)) {
if (all(sapply(.Object#X, function(x) class(x) == "A")))
TRUE
else
"'Avector' must be a list of elements in the class 'A'"
}
)
# Define a method to subscript the elements inside of the vector
setMethod(
"[", signature(x = "Avector", i = "ANY", j = "ANY"),
function(x, i, j, ...) x#X[[i]]
)
# Test the class
a1 <- new("A", x = 1)
a2 <- new("A", x = 2)
avec <- new("Avector", X = list(a1, a2))
# Retrieve the element in index i
avec[i]
This method appears more like a hack to me. Is there a way to do this in a canonical way in R without doing this type checking and indexing method by hand?
Edit:
This should also hold, if the class A is not consisting of atomic slots. For example in the case that:
setClass("A", representation(x = "data.frame"))
I would be glad for help :)
Cheers,
Adrian
The answer depends somewhat on what you are trying to accomplish, and may or may not be possible in your use case. The way S4 is intended to work is that objects are supposed to be high-level to avoid excessive overheads.
Generally, it is necessary to have the slots be vectors. You can't define new atomic types from within R. So in your toy example instead of calling
avec <- new("Avector", X = list(a1, a2))
you call
avec <- new("A", x = c(1, 2))
This may necessitate other slots (which were previously vectors) becoming arrays, for example.
If you're desperate to have an atomic type, then you might be able to over-ride one of the existing types. I think the bit64 package does this, for example. Essentially what you do is make a new class that inherits from, say, numeric and then write lots of methods that supersede all the default ones for your new class.

In Kotlin, how to check contains one or another value?

In Kotlin we can do:
val arr = intArrayOf(1,2,3)
if (2 in arr)
println("in list")
But if I want to check if 2 or 3 are in arr, what is the most idiomatic way to do it other than:
if (2 in arr || 3 in arr)
println("in list")
I'd use any() extension method:
arrayOf(1, 2, 3).any { it == 2 || it == 3 }
This way, you traverse the array only once and you don't create a set instance just to check whether it's empty or not (like in one of other answers to this question).
This is the shortest and most idiomatic way I can think of using any and in:
val values = setOf(2, 3)
val array = intArrayOf(1, 2, 3)
array.any { it in values }
Of course you can use a functional reference for the in operator as well:
array.any(values::contains)
I use setOf for the first collection because order does not matter.
Edit: I switched values and array, because of alex.dorokhow's answer. The order doesn't matter for the check to work but for performance.
The OP wanted the most idiomatic way of solving this. If you are after a more efficient way, go for aga's answer.
You can use intersect method, it takes iterable as paramter and returns set containing only items that are both in your collection and in iterable you provided. Then on that set you just need to do size check.
Here is sample:
val array1 = arrayOf(1, 2, 3, 4, 5, 6)
val array2 = arrayOf(2, 5)
// true if array1 contains any of the items from array2
if(array1.intersect(array2.asIterable()).isNotEmpty()) {
println("in list")
}
Combining #aga and #willi-mentzel solutions for better efficiency and dynamic set of checked values:
val numbers = setOf(2, 3)
arrayOf(1, 2, 3).any(numbers::contains)
Is this case the array will be iterated completely only once (at most, in the worst case).
This is more efficient than (suggested by #WilliMentzel):
numbers.any(arrayOf(1, 2, 3)::contains) // don't do that!
Where the array will be iterated set.count times in the worst case.
Note that Set.contains has O(1) complexity, but IntArray::contains has O(N).
Of course, this optimization makes sense only if the set or array are big enough.
Another handy way is actually not Kotlin's but with use of Java Collections.
It is also good to know it.
Collections.disjoint(Collection<?> c1, Collection<?> c2)
Returns {#code true} if the two specified collections have no elements
in common.
#Test
fun disjointCollections() {
val list = listOf(1, 2, 3)
assertTrue(Collections.disjoint(list, listOf(7, 8)))
assertFalse(Collections.disjoint(list, listOf(1)))
}
For me, the best way to solve this is to define a containsAny(elements:) extension function on the Array and/or Collection class. All of the places where you need to check whether an Array or Collection contains any of the elements of another then remains nice and neat, as follows:
arrayOf(1, 2, 3).containsAny(2, 3)
The implementation detail is tucked away inside of that function and can be changed in a single place in future should you wish to change the implementation.
Here's an example implementation of an extension function defined on the Collection class, the details of which are inspired by other answers in this thread:
/**
* Returns true if the receiving collection contains any of the specified elements.
*
* #param elements the elements to look for in the receiving collection.
* #return true if any element in [elements] is found in the receiving collection.
*/
fun <T> Collection<T>.containsAny(vararg elements: T): Boolean {
return containsAny(elements.toSet())
}
/**
* Returns true if the receiving collection contains any of the elements in the specified collection.
*
* #param elements the elements to look for in the receiving collection.
* #return true if any element in [elements] is found in the receiving collection.
*/
fun <T> Collection<T>.containsAny(elements: Collection<T>): Boolean {
val set = if (elements is Set) elements else elements.toSet()
return any(set::contains)
}
Likewise, here's an extension function defined on the Array class:
/**
* Returns true if the receiving array contains any of the specified elements.
*
* #param elements the elements to look for in the receiving array.
* #return true if any element in [elements] is found in the receiving array.
*/
fun <T> Array<T>.containsAny(vararg elements: T): Boolean {
return any(elements.toSet()::contains)
}
I think it's most readable to write the statement the other way around:
val arr = intArrayOf(1,2,3)
val match = setOf(2, 3).any(arr::contains)
It might be even possible to use ranges in certain scenarios:
val match = (2..3).any(arr::contains)
In the end, your solution looks pretty good to me already. Although not using fancy library functionality.
You can make an extension function to check for more values:
infix fun <T> Iterable<T>.containsAny(values: Iterable<T>): Boolean =
intersect(values).isNotEmpty()
Have a look at this blog post: https://www.codevscolor.com/kotlin-check-array-contains-one-multiple-values
Sample code
fun main() {
val givenArray = intArrayOf(1, 2, 3, 4, 5, 7, 9, 11)
println(givenArray.any{ it == 5 || it == 12})
println(givenArray.any{ it == 5 || it == 11})
println(givenArray.any{ it == 15 || it == 21})
}
If you use Apache Commons in your project, you can use CollectionUtils.containsAny.
we can use any() funtion and a Set
val arr = intArrayOf(1,2,3)
if(arr.any{ it in setOf(2,3) })
println("in list")

Scala case class arguments instantiation from array

Consider a case class with a possibly large number of members; to illustrate the case assume two arguments, as in
case class C(s1: String, s2: String)
and therefore assume an array with size of at least that many arguments,
val a = Array("a1", "a2")
Then
scala> C(a(0), a(1))
res9: C = c(a1,a2)
However, is there an approach to case class instantiation where there is no need to refer to each element in the array for any (possibly large) number of predefined class members ?
No, you can't. You cannot guarantee your array size is at least the number of members of your case class.
You can use tuples though.
Suppose you have a mentioned case class and a tuple that looks like this:
val t = ("a1", "a2")
Then you can do:
c.tupled(t)
Having gathered bits and pieces from the other answers, a solution that uses Shapeless 2.0.0 is thus as follows,
import shapeless._
import HList._
import syntax.std.traversable._
val a = List("a1", 2) // List[Any]
val aa = a.toHList[String::Int::HNil]
val aaa = aa.get.tupled // (String, Int)
Then we can instantiate a given case class with
case class C(val s1: String, val i2: Int)
val ins = C.tupled(aaa)
and so
scala> ins.s1
res10: String = a1
scala> ins.i2
res11: Int = 2
The type signature of toHList is known at compile time as much as the case class members types to be instantiate onto.
To convert a Seq to a tuple see this answer: https://stackoverflow.com/a/14727987/2483228
Once you have a tuple serejja's answer will get you to a c.
Note that convention would have us spell c with a capital C.

incredible implicit Array conversion in scala

According to Scaladoc, there is no method named map in Array class, but there is an implicit function implicit def intArrayOps (xs: Array[Int]): ArrayOps[Int] defined in scala.Predef. So you can apply map on Array(1,2,3,4) if you like. But What I am confused about is that the map result is of type Array[Int], not ArrayOps[Int]. Here is my test:
scala> val array = Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)
scala> array.map(x => x)
res18: Array[Int] = Array(1, 2, 3, 4)
scala> res18.isInstanceOf[Array[Int]]
res19: Boolean = true
scala> res18.isInstanceOf[scala.collection.mutable.ArrayOps[Int]]
warning: there wre 1 unchecked warnings; re-run with -unchecked for details
res20: Boolean = false
It indeed returns an array, as intended and as is convenient, there is no reason you would need an ArrayOps, it is intended only to provide extra methods to arrays. The doc is wrong.
The routine is actually not implemented in ArrayOps. As most collection methods, it is inherited from TraversableLike. And you see two map methods in the doc:
def map [B] (f: (T) ⇒ B): ArrayOps[B]
def map [B, That] (f: (T) ⇒ B)(implicit bf: CanBuildFrom[Array[T], B, That]): That
Only the second one exists (inherited from TraversableLike). It is intended to allow implementation of map in just one place (traversable like) while allways giving the best possible behavior. For instance, a String is a of Seq[Char], if you map with a function from character to character, you get a String, but if you map from collection to say Int, the result cannot be a String and it will just be a Seq. This is explained in much detail in the paper fighting the bit rot with types.
However, this makes for a very complex signature, which does not reflect the simplicity of using the method, and makes very poor documentation most of the time (you normally would have to chase to which CanBuildFrom in implicit scope would work). This was discussed in this most famous scala question of stack overflow. So the tool scaladoc was extended so that a simpler entry, corresponding to intended usage, may appear. If you look at the source of GenTraversableLike, where the routine is introduced, you will see the following in the scaladoc for map (and a similar one in many methods)
#usecase def map[B](f: A => B): $Coll[B]
Subtypes add in their doc #define Coll <className>, and map (among others) appears with the simplified signature, marked [Use case]. In the source of ArrayOps, there is a #define Coll ArrayOps where it should be Array.
You can use the REPL with the -Xprint:typer option to see what's going on. Here is the output of the map method, reformatted for easier reading:
$ scala -Xprint:typer
scala> Array(1,2,3,4).map(x => x)
[[syntax trees at end of typer]]// Scala source: <console>
// some lines deleted
private[this] val res0: Array[Int] =
scala.this.Predef.intArrayOps(scala.Array.apply(1, 2, 3, 4))
.map[Int, Array[Int]]
(( (x: Int) => x ))
(scala.this.Array.canBuildFrom[Int](reflect.this.Manifest.Int));
So simplifying for package names here is what happens:
intArrayOps(Array(1,2,3,4)) // converts to ArrayOps
.map[Int, Array[Int]] // calls map with parameter lists below
((x:Int) => x) // pass identity function as fisrt param
(Array.canBuildFrom[Int]// pass builder for Array[Int] as second param
(Manifest.Int)) // pass class manifest for Int
So there is indeed a conversion to ArrayOps (first line). It returns ArrayOps[Int].
The ArrayOps.map[Int, Array[Int]] method is then called on it. Then as didierd explain, the original signature for map - not the simplified signature - indicates that the return type inferred will be Array[Int]

Resources