[SCALA] 서열에서 만족 조건 X 그 첫 번째 요소를 찾기
SCALA서열에서 만족 조건 X 그 첫 번째 요소를 찾기
일반적으로, 어떻게 서열의 특정 조건을 만족하는 첫 번째 요소를 찾는 방법은?
예를 들어, 나는 가능한 날짜 형식의 목록을 가지고 있고, 나는 나의 날짜 문자열을 구문 분석 할 수있는 첫 번째 형식의 구문 분석 된 결과를 찾고 싶어요.
val str = "1903 January"
val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy")
.map(new SimpleDateFormat(_))
formats.flatMap(f => {try {
Some(f.parse(str))
}catch {
case e: Throwable => None
}}).head
나쁘지 않다. 그러나 1. 조금 추한. 2. 그것은 ( "MM 일"및 "MM, YYYY"형식 시도) 일부 불필요한 작업을했다. 아마도 더 우아하고 관용적 인 방법은 무엇입니까? (반복자를 사용하고 계십니까?)
해결법
-
==============================
1.있는 거 확신 적어도 하나의 의지 형식이 성공하면 경우 :
있는 거 확신 적어도 하나의 의지 형식이 성공하면 경우 :
formats.view.map{format => Try(format.parse(str)).toOption}.filter(_.isDefined).head
당신은 조금 더 안전 할하려는 경우 :
formats.view.map{format => Try(format.parse(str)).toOption}.find(_.isDefined)
시도는 스칼라 2.10 년에 도입되었다.
보기는 느리게 값을 계산하는 컬렉션의 유형이다. 정의 된 첫 번째 하나를 찾을 필요가있다 그것은 컬렉션 만 많은 항목에 시도 내에서의 코드를 적용합니다. 첫 번째 형식은 문자열에 적용되는 경우, 다음은 문자열로 나머지 형식을 적용하려고하지 않을 것이다.
-
==============================
2.당신은 순서에 찾기 방법을 사용해야합니다. 일반적으로 당신은 내장 선호한다 방법, 그들은 특정 순서에 최적화 될 수 있기 때문이다.
당신은 순서에 찾기 방법을 사용해야합니다. 일반적으로 당신은 내장 선호한다 방법, 그들은 특정 순서에 최적화 될 수 있기 때문이다.
Console println List(1,2,3,4,5).find( _ == 5) res: Some(5)
즉 경기 첫하여 SimpleDateFormat을 반환한다 :
val str = "1903 January" val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy") .map(new SimpleDateFormat(_)) formats.find { sdf => sdf.parse(str, new ParsePosition(0)) != null } res: Some(java.text.SimpleDateFormat@ef736ccd)
처리되고있다 먼저 날짜를 반환 :
val str = "1903 January" val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy").map(new SimpleDateFormat(_)) val result = formats.collectFirst { case sdf if sdf.parse(str, new ParsePosition(0)) != null => sdf.parse(str) }
또는 게으른 모음을 사용합니다 :
val str = "1903 January" val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy").map(new SimpleDateFormat(_)) formats.toStream.flatMap { sdf => Option(sdf.parse(str, new ParsePosition(0))) }.headOption res: Some(Thu Jan 01 00:00:00 EET 1903)
-
==============================
3.이것은 불필요한 평가를 방지 할 수 있습니다.
이것은 불필요한 평가를 방지 할 수 있습니다.
formats.collectFirst{ case format if Try(format.parse(str)).isSuccess => format.parse(str) }
해석에있어서의 평가의 수는 시도 + 1의 수이다.
-
==============================
4.스칼라 추출기와 게으름과 같은 버전 :
스칼라 추출기와 게으름과 같은 버전 :
case class ParseSpec(dateString: String, formatter:DateTimeFormatter) object Parsed { def unapply(parsableDate: ParseSpec): Option[LocalDate] = Try( LocalDate.parse(parsableDate.dateString, parsableDate.formatter) ).toOption } private def parseDate(dateString: String): Option[LocalDate] = { formats.view. map(ParseSpec(dateString, _)). collectFirst { case Parsed(date: LocalDate) => date } }
-
==============================
5.그 첫 번째 요소의 일치 조건 (있는 경우)의 옵션을 반환로 바로 찾기 방법을 사용하십시오
그 첫 번째 요소의 일치 조건 (있는 경우)의 옵션을 반환로 바로 찾기 방법을 사용하십시오
formats.find(str => Try(format.parse(str)).isSuccess)
또한, 실행은 첫 번째 하나를 따기 전에 세트의 모든 요소를 분석하려고하지 않습니다 그래서, 첫 경기에서 멈 춥니 다. 다음은 그 예이다 :
def isSuccess(t: Int) = { println(s"Testing $t") Math.floorMod(t, 3) == 0 } isSuccess: isSuccess[](val t: Int) => Boolean List(10, 20, 30, 40, 50, 60, 70, 80, 90).filter(isSuccess).headOption Testing 10 Testing 20 Testing 30 Testing 40 Testing 50 Testing 60 Testing 70 Testing 80 Testing 90 res1: Option[Int] = Some(30) Stream(10, 20, 30, 40, 50, 60, 70, 80, 90).filter(isSuccess).headOption Testing 10 Testing 20 Testing 30 res2: Option[Int] = Some(30) List(10, 20, 30, 40, 50, 60, 70, 80, 90).find(isSuccess) Testing 10 Testing 20 Testing 30 res0: Option[Int] = Some(30)
스트림 것이 정말 중요하지 않습니다. 당신은 예를 들어 인 IntelliJ를 사용하고 또한 경우에 당신을 제안합니다 :
seq.filter(p).headOption
seq.find(p)
-
==============================
6.
scala> def parseOpt(fmt: SimpleDateFormat)(str: String): Option[Date] = | Option(fmt.parse(str, new ParsePosition(0))) tryParse: (str: String, fmt: java.text.SimpleDateFormat)Option[java.util.Date] scala> formats.view.flatMap(parseOpt(fmt)).headOption res0: Option[java.util.Date] = Some(Thu Jan 01 00:00:00 GMT 1903)
그런데, SimpleDateFormat에 이후 수단 위의 코드는 스레드로부터 안전하지 않습니다 것을 하나, 비 스레드 안전합니다!
-
==============================
7.나는 꼬리 재귀를 사용하는 것이 훨씬 낫다 가장 효율적인 솔루션은 지금까지 여기에 제공되는 지금까지 생각 :
나는 꼬리 재귀를 사용하는 것이 훨씬 낫다 가장 효율적인 솔루션은 지금까지 여기에 제공되는 지금까지 생각 :
implicit class ExtendedIterable[T](iterable: Iterable[T]) { def findFirst(predicate: (T) => Boolean): Option[T] = { @tailrec def findFirstInternal(remainingItems: Iterable[T]): Option[T] = { if (remainingItems.nonEmpty) if (predicate(remainingItems.head)) Some(remainingItems.head) else findFirstInternal(remainingItems.tail) else None } findFirstInternal(iterable) } }
그것은 단순히 당신이 필요한 곳마다 다음과 같은 일을 할 수있는 위의 클래스를 가져 오기에 당신을 허용합니다 :
formats.findFirst(format => Try(format.parse(str)).isSuccess)
행운을 빌어 요!
from https://stackoverflow.com/questions/16883591/find-the-first-element-that-satisfies-condition-x-in-a-seq by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 아파치 스파크는 기존 DataFrame에 "CASE ... ELSE ..."계산 된 열을 추가 (0) | 2019.11.21 |
---|---|
[SCALA] 어떻게 오른쪽 연관 중위 연산자를 만드는 방법? (0) | 2019.11.21 |
[SCALA] 어떻게 불변 인 Set 비교 방법으로 사용되는 사용자 정의 평등 작업을 정의 할 수 있습니다 (0) | 2019.11.21 |
[SCALA] 효율적으로 스칼라의 문자 / 문자열을 n 번 반복 (0) | 2019.11.21 |
[SCALA] 슬릭 2.0 일반 CRUD 작업 (0) | 2019.11.21 |