سؤال

لدي قائمة 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 سيظهر أداء مختلف - معظمهم سيكون أسوأ.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top