Good afternoon! I'm using Scala and I want to match first three element of a list and the last one, no matter how much of them are in the list.
val myList:List[List[Int]] = List(List(3,1,2,3,4),List(23,45,6,7,2),List(3,3,2,1,5,34,43,2),List(8,5,3,34,4,5,3,2),List(3,2,45,56))
def parse(lists: List[Int]): List[Int] = lists.toArray match{
case Array(item, site, buyer, _*, date) => List(item, site, buyer, date)}
myList.map(parse _)
But I get : error: bad use of _* (a sequence pattern must be the last pattern)
I understand why I get it, but how can I avoid?
My use case is that I'm reading from hdfs, and every file has exact N (N is constant and equal for all files) columns, so I want to match only some of them, without writing something like case Array(item1, item2 , ..., itemN) => List(item1, item2, itemK, itemN)
Thank you!
You do not need to convert lists to Arrays, because lists are designed for pattern matching.
scala> myList match {
case item :: site :: buyer :: tail if tail.nonEmpty =>
item :: site :: buyer :: List(tail.last)
}
res3: List[List[Int]] = List(List(3, 1, 2, 3, 4), List(23, 45, 6, 7, 2),
List(3, 3, 2, 1, 5, 34, 43, 2), List(3, 2, 45, 56))
Or even more concise solution suggested by Kolmar
scala> myList match {
case item :: site :: buyer :: (_ :+ date) => List(item, site, buyer, date)
}
Related
I have an array of elements (numbers in my case)
var myArray= Array(1, 2, 3, 4, 5, 6)
//myArray: Array[Int] = Array(1, 2, 3, 4, 5, 6)
and I want to obtain a tuple than contain all of them:
var whatIwant= (1,2,3,4,5,6)
//whatIwant: (Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6)
I tried the following code but it doesn't work:
var tuple = myArray(0)
for (e <- myArray)
{
var tuple = tuple :+ e
}
//error: recursive variable tuple needs type
The trivial answer is this:
val whatIwant =
myArray match {
case Array(a, b, c, d, e, f) => (a, b, c, d, e, f)
case _ => (0, 0, 0, 0, 0, 0)
}
If you want to support different numbers of element in myArray then you are in for a world of pain because you will lose all the type information associated with a tuple.
If you are using Spark you should probably use its mechanisms to generate the data you want directly rather than converting to Array first.
The number of elements of a tuple is not infinitely superimposed. In earlier versions, there were only 22 at most. Scala treats tuples with different numbers of elements as different classes. So you can't add elements like a list.
Apart from utilizing metaprogramming techniques such as reflection, tuple objects may only be generated explicitly.
Before to mark this question as duplicated, I already read this topic: Haskell read Integer and list of lists from file and the solution doesn't solve my problem.
I'm trying to read the content in a File that contains this structure:
String, String, [(Int, Int, Int)]
The file looks something like this:
Name1 22/05/2018 [(1, 5, 10), (2, 5, 5), (3, 10, 40)]
Name2 23/05/2018 [(1, 10, 10), (2, 15, 5), (3, 50, 40),(4,20,5)]
Name3 22/05/2018 [(4, 2, 1), (5, 2, 2), (6, 50, 3), (1,2,3)]
Name4 23/05/2018 [(1, 3, 10), (2, 1, 5), (3, 2, 40), (6,20,20)]
In Haskell, I created this function to read the contents of the file and "convert" this content to my custom type.
rlist :: String -> [(Int, Int, Int)]
rlist = read
loadPurchases :: IO [(String, String, [(Int, Int, Int)])]
loadPurchases = do s <- readFile "tes.txt"
return (glpurch (map words (lines s)))
glpurch :: [[String]] -> [(String, String, [(Int, Int, Int)])]
glpurch [] = []
gplpurch ([name, dt, c]:r) = (name, dt, (rlist c)) : gplpurch r
But when I try to execute the "loadPurchases" function, I get this error:
Non-exhaustive patterns in function glpurch.
Using :set -Wall, I received this help message:
<interactive>:6:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for `glpurch':
Patterns not matched:
([]:_:_)
([_]:_)
([_, _]:_)
((_:_:_:_:_):_)
My problem is how to create all these conditions.
I will be very grateful if anyone can help me create those conditions that are likely to determine the "stopping condition"
You are only matching lists of length 3 when in fact there are many more words on each line. Just try it in GHCi:
> words "Name1 22/05/2018 [(1, 5, 10), (2, 5, 5), (3, 10, 40)]"
["Name1","22/05/2018","[(1,","5,","10),","(2,","5,","5),","(3,","10,","40)]"]
You probably want to recombine all words past the first two:
glpurch ((name : dt : rest) :r) = (name, dt, (rlist $ unwords rest)) : gplpurch r
To solve my problem, I did what #Welperooni and #Thomas M. DuBuisson suggested.
I added this code to my function:
glpurch ((name: dt: c: _): r) = (name, dt, (read c :: [(Cod, Quant, Price)
And I removed the blanks that were in the list in my file, these spaces made the division of the text not done correctly.
I am trying to find the common strings in a map and an array to output the respective values(from map, values here is Map[key -> value]) in Scala, I'm trying to not use any loops. Example:
Input:
Array("Ash","Garcia","Mac") Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
Output:
Array(5,4)
The output is an array with 5 and 4 because Ash and Mac are common in both the data structures
What constitutes a loop?
def common(arr: Array[String], m: Map[String,Int]): Array[Int] =
arr flatMap m.get
Usage:
common(Array("Ash","Garcia","Mac")
,Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3))
// res0: Array[Int] = Array(5, 4)
This is the most elegant solution, I think, but the results may not fit your requirements if there are duplicates in the array.
yourArray.collect(yourMap) // Array(5,4)
Use .filter to find the matching entries only, then get the value of your filtered map.
Given
scala> val names = Array("Ash","Garcia","Mac")
names: Array[String] = Array(Ash, Garcia, Mac)
scala> val nameToNumber = Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
nameToNumber: scala.collection.immutable.Map[String,Int] = Map(Ash -> 5, Mac -> 4, Lucas -> 3)
.filter.map
scala> nameToNumber.filter(x => names.contains(x._1)).map(_._2)
res3: scala.collection.immutable.Iterable[Int] = List(5, 4)
Alternatively, you can use collect,
scala> nameToNumber.collect{case kv if names.contains(kv._1) => kv._2}
res6: scala.collection.immutable.Iterable[Int] = List(5, 4)
Your complexity here is O(n2)
Quite easy for scala elegant syntax:
val a = Array("Ash","Garcia","Mac")
val m = Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
println(m.filter { case (k, v) => a.contains(k)}.map { case (k, v) => v}.toArray)
Here is the solution!
val Array(direction, value, power, type, zone) = Array(1, 2, 3, 4, 5)
Is there any way to refer Array(1, 2, 3, 4, 5) from some reference that we can use to perform other array operations like iterating array, etc..
i want to use direction, value, power, type, zone as they are more meaningful rather then using arr(0), arr(1), etc.. in addition to doing regular operations on array
You can define your array as follows:
val arr # Array(direction, value, power, t, zone) = Array(1, 2, 3, 4, 5)
This way you can use arr as a normal Array and the other "meaningful" vals.
Note that I changed type by t because the first one is a reserved word of the language.
If you want the object to have meaningful accessors to the values it is containing, I would suggest to simply use a case class:
case class MyDataClass(direction: Int, values: Int, power: Int, type: Int, zone: Int)
val d = MyDataClass(1, 2, 3, 4, 5)
val dir = d.direction
To use it as you would with a traditional array, I would add an implicit conversion to Array[Int]
Store the array as normal, then def the elements as indexes into the array.
val array = Array(1,2,3,4,5)
def direction = array(0)
// etc.
This will still work inside of other methods as Scala allows methods in methods.
Am I missing something here? Why not just do
val arr = Array(1, 2, 3, 4, 5)`
and then subscript the individual elements (arr(0), arr(1), etc.) when you need them?
In Python, this is how I would do it.
>>> x
array([10, 9, 8, 7, 6, 5, 4, 3, 2])
>>> x[np.array([3, 3, 1, 8])]
array([7, 7, 9, 2])
This doesn't work in the Scala Spark shell:
scala> val indices = Array(3,2,0)
indices: Array[Int] = Array(3, 2, 0)
scala> val A = Array(10,11,12,13,14,15)
A: Array[Int] = Array(10, 11, 12, 13, 14, 15)
scala> A(indices)
<console>:28: error: type mismatch;
found : Array[Int]
required: Int
A(indices)
The foreach method doesn't work either:
scala> indices.foreach(println(_))
3
2
0
scala> indices.foreach(A(_))
<no output>
What I want is the result of B:
scala> val B = Array(A(3),A(2),A(0))
B: Array[Int] = Array(13, 12, 10)
However, I don't want to hard code it like that because I don't know how long indices is or what would be in it.
The most concise way I can think of is to flip your mental model and put indices first:
indices map A
And, I would potentially suggest using lift to return an Option
indices map A.lift
You can use map on indices, which maps each element to a new element based on a mapping lambda. Note that on Array, you get an element at an index with the apply method:
indices.map(index => A.apply(index))
You can leave off apply:
indices.map(index => A(index))
You can also use the underscore syntax:
indices.map(A(_))
When you're in a situation like this, you can even leave off the underscore:
indices.map(A)
And you can use the alternate space syntax:
indices map A
You were trying to use foreach, which returns Unit, and is only used for side effects. For example:
indices.foreach(index => println(A(index)))
indices.map(A).foreach(println)
indices map A foreach println