Как сделать так, чтобы метод возвращал то же самое, что и входные данные? - PullRequest
11 голосов
/ 11 июня 2019

Я хочу разбить строку, разделенную запятыми, и использовать результат как Seq или Set:

def splitByComma(commaDelimited: String): Array[String]
  = commaDelimited.trim.split(',')

def splitByCommaAsSet(commaDelimited: String): Set[String]
  = splitByComma(commaDelimited).toSet

def splitByCommaAsSeq(commaDelimited: String): Seq[String]
  = splitByComma(commaDelimited).toSeq

val foods = "sushi,taco,burrito"
val foodSet = splitByCommaAsSet(foods)
// foodSet: scala.collection.immutable.Set[String] = Set(sushi, taco, burrito)
val foodSeq = splitByCommaAsSeq(foods)
// foodSeq: Seq[String] = List(sushi, taco, burrito)

Однако это довольно повторяющееся. В идеале я хотел бы иметь что-то вроде genericSplitByComma[Set](foods), которое просто возвращает Set, когда я передаю Set, и возвращает Seq, когда я передаю Seq.

Ответы [ 3 ]

13 голосов
/ 11 июня 2019

@ KrzysztofAtłasik отлично работает для Scala 2.12.
Это решение для 2.13. (Не совсем уверен, что это лучший способ) .

import scala.collection.Factory
import scala.language.higherKinds

def splitByComma[C[_]](commaDelimited: String)(implicit f: Factory[String, C[String]]): C[String] =
  f.fromSpecific(commaDelimited.split(","))
  // Or, as Dmytro stated, which I have to agree looks better.
  commaDelimited.split(",").to(f)

Который вы можете использовать так:

splitByComma[Array]("hello,world!")
// res: Array[String] = Array(hello, world!)

splitByComma[Set]("hello,world!")
// res: Set[String] = Set(hello, world!)

splitByComma[List]("hello,world!")
// res: List[String] = List(hello, world!)
11 голосов
/ 11 июня 2019

В Scala есть метод с именем to, который может преобразовать произвольную коллекцию в другую, если в области видимости есть класс типов с именем CanBuildFrom.

import scala.collection.generic.CanBuildFrom
import scala.languageFeature.higherKinds

def genericSplitByComma[S[_]](s: String)(implicit cbf: CanBuildFrom[Nothing, String, S[String]]): S[String] = {
    s.split(",").to[S]
}

genericSplitByComma[Set]("Hello, hello") //Set(Hello,  hello)
genericSplitByComma[List]("Hello, hello") //List(Hello,  hello)
genericSplitByComma[Array]("Hello, hello") //Array(hello, world!)

Нам не нужно ограничивать S[_], потому что эта функция не будет компилироваться, если нет подходящего CanBuildFrom в области видимости. Например, это не удастся:

genericSplitByComma[Option]("Hello, hello")

Ниже также произойдет сбой, потому что наш конструктор типов S[_] принимает только один аргумент типа, а карта ожидает два:

genericSplitByComma[Map]("Hello, hello")

Как заметили Луис Мигель Мехия Суарес и Дмитрий Митин, в коллекциях только что выпущенного Scala 2.13 было главный рефактор , поэтому он будет работать до Scala 2.12.

6 голосов
/ 11 июня 2019

Для этого есть простой обходной путь.Не совсем запрошенный синтаксис, но такой же краткий, и он должен быть совместим с 2.13.

def simpleSplitByComma(coll :Iterable[String]) =
  coll.flatMap(_.trim.split(","))

simpleSplitByComma(Set("hello,world"))          //res0: Set(hello, world)
simpleSplitByComma(Seq("bellow,world"))         //res1: List(bellow, world)
simpleSplitByComma(Array("fellow,old"))         //res2: ArrayBuffer(fellow, old)
simpleSplitByComma(Stream("end,of,the,world"))  //res3: Stream(end, ?)
...