عودة Scala في البداية في القائمة
-
30-09-2019 - |
سؤال
لدي قائمة l:List[T1]
وهو حاليا أفعل ما يلي:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
ال myfun
تقوم الوظيفة بإرجاع أي شيء أو بعض ، ويرمي كل ما لا شيء ويجد إرجاع العنصر الأول من القائمة إن وجد.
هذا يبدو خارقة بعض الشيء بالنسبة لي. أنا أعتقد أنه قد يكون هناك بعض الفهم أو ما شابه ذلك سيفعل ذلك أقل إهدارا أو أكثر ذكاء. على سبيل المثال: لا أحتاج إلى أي إجابات لاحقة إذا myfun
عائدات أي Some
أثناء ال map
من القائمة l
.
المحلول
ماذا عن:
l.toStream flatMap (myfun andThen (_.toList)) headOption
الدفق كسول ، لذلك لن يخطط لكل شيء مقدمًا ، لكنه لن يعيد تجديد الأشياء أيضًا. بدلاً من تسطيح الأشياء ، قم بتحويل Option
إلى List
لهذا السبب. flatMap
من الممكن استخدامه.
نصائح أخرى
حسنًا ، هذا تقريبا ، ولكن ليس تماما
val x = (l flatMap myfun).headOption
لكنك تعود Option
بدلا من List
من Myfun ، لذلك قد لا يعمل هذا. إذا كان الأمر كذلك (ليس لدي استعراض) ، فحاول بدلاً من ذلك:
val x = (l flatMap(myfun(_).toList)).headOption
بالإضافة إلى استخدام toStream
لجعل البحث كسول ، يمكننا استخدامه Stream::collectFirst
:
List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None
هذه:
يحول
List
الىStream
من أجل إيقاف البحث مبكرًا.يحول العناصر باستخدام
myFun
كماOption[T]
س.يجمع أول عنصر تم تعيينه
None
واستخراجها.
بدء Scala 2.13
, ، مع إهمال Stream
ق لصالح LazyList
ق ، سيصبح هذا:
List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }
حسنًا ، ما يعادل الفهود سهل للغاية
(for(x<-l, y<-myfun(x)) yield y).headOption
الذي ، إذا قمت بالفعل بالترجمة ، تعمل على نفس ما قدمه Oxbow_lakes. بافتراض كسل معقول للقائمة.
اعتبارًا من عام 2017 ، يبدو أن الإجابات السابقة قديمة. قمت بتشغيل بعض المعايير (قائمة 10 ملايين ints ، المباراة الأولى تقريبًا في الوسط ، Scala 2.12.3 ، Java 1.8.0 ، 1.8 GHz Intel Core I5). ما لم يذكر خلاف ذلك، list
و map
لديك الأنواع التالية:
list: scala.collection.immutable.List
map: A => Option[B]
ببساطة اتصل map
في القائمة: ~ 1000 مللي ثانية
list.map(map).find(_.isDefined).flatten
اول مكالمة toStream
في القائمة: ~ 1200 مللي ثانية
list.toStream.map(map).find(_.isDefined).flatten
مكالمة toStream.flatMap
في القائمة: ~ 450 مللي ثانية
list.toStream.flatMap(map(_).toList).headOption
مكالمة flatMap
في القائمة: ~ 100 مللي ثانية
list.flatMap(map(_).toList).headOption
اول مكالمة iterator
في القائمة: ~ 35 مللي ثانية
list.iterator.map(map).find(_.isDefined).flatten
وظيفة العودية find()
: ~ 25 مللي ثانية
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
list match {
case Nil => None
case head::tail => map(head) match {
case None => find(tail, map)
case result @ Some(_) => result
}
}
}
وظيفة التكرار find()
: ~ 25 مللي ثانية
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
for (elem <- list) {
val result = map(elem)
if (result.isDefined) return result
}
return None
}
يمكنك زيادة تسريع الأشياء باستخدام Java بدلاً من مجموعات Scala وأسلوب أقل وظيفية.
حلقة على المؤشرات في java.util.ArrayList
: ~ 15 مللي ثانية
def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result.isDefined) return result
i += 1
}
return None
}
حلقة على المؤشرات في java.util.ArrayList
مع عودة الوظيفة null
بدلاً من None
: ~ 10 مللي ثانية
def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result != null) return Some(result)
i += 1
}
return None
}
(بالطبع ، عادة ما يعلن المرء نوع المعلمة باسم java.util.List
, ، ليس java.util.ArrayList
. اخترت الأخير هنا لأنه الفصل الذي استخدمته في المعايير. تطبيقات أخرى من java.util.List
سيظهر أداء مختلف - معظمهم سيكون أسوأ.)