How to flatten named tuples in a tuple in julia? - tuples

I have a Tuple of elements, some of which are NamedTuples. I would like to flatten the NamedTuples like so:
julia> nt = (a="a", b="b")
(a = "a", b = "b")
julia> t = (1, 2, 3, nt)
(1, 2, 3, (a = "a", b = "b"))
julia> res = tuple(1, 2, 3, nt...)
(1, 2, 3, "a", "b")
How to do this programmatically? I tried the following:
julia> exprs = [x isa NamedTuple ? Meta.parse("$x...") : x for x in t]
4-element Array{Any,1}:
1
2
3
:((a = "a", b = "b")...)
julia> res = tuple(eval(ex) for ex in exprs)
(Base.Generator{Array{Any,1},typeof(eval)}(Base.MainInclude.eval, Any[1, 2, 3, :((a = "a", b = "b")...)]),)
But it doesn't quite give what I would like:
(1, 2, 3, "a", "b")

The simplest way to do it would be to write:
julia> Tuple(Iterators.flatten((1,2,3, (a="a",b="b"))))
(1, 2, 3, "a", "b")
this has a downside that it is type unstable and that it will flatten all iterables (not only NamedTuples).
If you want only NamedTuples flattened then something like this could be used:
julia> Tuple(reduce((a,b) -> (b isa NamedTuple ? append! : push!)(a, b), (1,2,3, (a="a",b="b")), init=[]))
(1, 2, 3, "a", "b")
(still it will be type unstable)
If you want something type stable you can use recursion e.g. like this:
flatten() = ()
flatten(a::NamedTuple) = Tuple(a)
flatten(a) = (a,)
flatten(a::NamedTuple, b...) = tuple(a..., flatten(b...)...)
flatten(a, b...) = tuple(a, flatten(b...)...)
flatten_tuple(x::Tuple) = flatten(x...)
and now you have:
julia> flatten_tuple((1,2,3, (a="a",b="b")))
(1, 2, 3, "a", "b")
julia> #code_warntype flatten_tuple((1,2,3, (a="a",b="b")))
Variables
#self#::Core.Compiler.Const(flatten_tuple, false)
x::Tuple{Int64,Int64,Int64,NamedTuple{(:a, :b),Tuple{String,String}}}
Body::Tuple{Int64,Int64,Int64,String,String}
1 ─ %1 = Core._apply_iterate(Base.iterate, Main.flatten, x)::Tuple{Int64,Int64,Int64,String,String}
└── return %1

Related

How to convert a Tuple{Array{Float64,1},Array{Float64,1}} to Array{Tuple{Float64,Float64},1} in julia

How may I convert a Tuple{Array{Float64,1},Array{Float64,1}} to Array{Tuple{Float64,Float64},1} ?
Code
#Sampling
function sam()
x = range(0, 10.0, length = 9) |> collect
y = range(0, 10.0, length = 9) |> collect
return (x,y)
end
xy = sam()
typeof(xy)
The code above returns this output:
Tuple{Array{Float64,1},Array{Float64,1}}
The easiest thing to do in your situation is to assign the output of your function to two separate variables, like this:
function foo()
x = [1, 2, 3]
y = [4, 5, 6]
return x, y
end
x, y = foo()
See the docs on multiple return values.
Then you can use zip to turn the vectors into an iterator of tuples:
julia> x, y = foo()
([1, 2, 3], [4, 5, 6])
julia> x
3-element Array{Int64,1}:
1
2
3
julia> y
3-element Array{Int64,1}:
4
5
6
julia> z = zip(x, y)
zip([1, 2, 3], [4, 5, 6])
Note that the output of zip is an iterator, rather than an array of tuples. You can either iterate through the elements of the iterator to get the individual tuples,
julia> foreach(println, z)
(1, 4)
(2, 5)
(3, 6)
or you can collect the iterator if you actually need an array of tuples:
julia> collect(z)
3-element Array{Tuple{Int64,Int64},1}:
(1, 4)
(2, 5)
(3, 6)

Scala How to match two list to a Map or tuple

val listA = List("one", "two", "three")
val listB = List(1, 3, 4, 9, 2, 6)
Result:
val m: Map[String, Int] = Map(one -> 1, two -> 2, three -> 3)
I want to pair listA and listB to a Map with corresponding key/value. I have tried to use the zip method but it only support sequential merging. How can I achieve the above result?
If f(x) is a function that can return the corresponding numerical value for the given alphabetical value, you can just map each x in listA to a pair (x, f(x)) and then turn the resulting list of pairs into a map using .toMap.
zip with sorted listB:
listA.zip(listB.sorted).toMap
Do you intend:
scala> val listA = List("one", "two", "three", "four")
listA: List[String] = List(one, two, three, four)
scala> val listB = List(1, 3, 4, 9, 2, 6)
listB: List[Int] = List(1, 3, 4, 9, 2, 6)
scala> val m = Map("one"->1, "two"->20, "three"->3)
m: scala.collection.immutable.Map[String,Int] = Map(one -> 1, two -> 20, three -> 3)
scala> listA flatMap { case k if (m contains k) && (listB contains m(k)) => Some(k, m(k)) ; case _ => None }
res4: List[(String, Int)] = List((one,1), (three,3))

How to get a set of all elements that occur multiple times in a list in Scala?

E.g. for List(1, 1, 1, 2, 3, 3, 4) it would be Set(1, 3), because 1 and 3 are the only elements which occur multiple times.
val s = List(1, 1, 1, 2, 3, 3, 4) // a list with non-unique elements
(s diff s.distinct) toSet // Set(1, 3)
A bit more convoluted but you can avoid having to call toSet.toList, first group the integers:
scala> s.groupBy(identity)
res13: scala.collection.immutable.Map[Int,List[Int]] =
Map(2 -> List(2), 4 -> List(4), 1 -> List(1, 1, 1), 3 -> List(3, 3))
Then collect only the one were the list has length greater as 1:
scala> s.groupBy(identity).collect { case (v, l) if l.length > 1 => v }
res17: scala.collection.immutable.Iterable[Int] = List(1, 3)
If you want a Set just call toSet.

Using the map-function with lists (SML)

I have made the function fun charListToInt (y) = map (fn x => Char.ord (x) - 64) y::[] that takes a char list and returns a int list list with the integer code of the character (A = 1, B = 2, C = 3...).
For example: charListToInt [#"A", #"B", #"C", #"D", #"E"] = [[1, 2, 3, 4, 5]].
What I really want to do is to give the function the type val charListToInt = fn : char list list -> int list list instead of just having char list as input, like this:
[[#"A", #"B"], [#"C", #"D"]] = [[1, 2], [3, 4]]
Can this really be done by using the map-function?
val charListListToIntListList = map (map (fn c => ord c - ord #"A" + 1))

How to merge tuples by same elements in Scala

For example, if I have the following tuples:
(1, "a", "l")
(1, "a", "m")
(1, "a", "n")
I want to merge them like this:
(1, "a", List("l", "m", "n"))
In my case, the lists are a result from an inner join using Slick.
So, the first and second elements (1 and "a") should be the same.
If somebody knows how to merge like that in case of using Slick, let me know please.
Or more generally, the way to merge tuples with inner lists by the same elements.
(1, "a", "l")
(1, "a", "m")
(1, "b", "n")
(1, "b", "o")
// to like this
List( (1, "a", List("l", "m")), (1, "b", List("n", "o")) )
How about:
val l = ??? // Your list
val groups = l groupBy { case (a, b, c) => (a,b) }
val tups = groups map { case ((a,b), l) => (a,b,l.map(_._3)) }
tups.toList
You could try foldRight
val l = List((1, "a", "l"), (1, "a", "m"), (1, "a", "n"), (1, "b", "n"), (1, "b", "o"))
val exp = List((1, "a", List("l", "m", "n")), (1, "b", List("n", "o")))
val result = l.foldRight(List.empty[(Int, String, List[String])]) {
(x, acc) =>
val (n, s1, s2) = x
acc match {
case (n_, s1_, l_) :: t if (n == n_ && s1 == s1_) =>
(n_, s1_, (s2 :: l_)) :: t
case _ =>
(n, s1, List(s2)) :: acc
}
}
println(result)
println(result == exp)
Update
If the input list is not sorted:
val result = l.sorted.foldRight(...)