স্কেলে সূচক সহ কার্যকর পুনরাবৃত্তি


83

যেহেতু স্কালার forসূচি সহ পুরানো জাভা স্টাইলের লুপ নেই,

// does not work
val xs = Array("first", "second", "third")
for (i=0; i<xs.length; i++) {
  println("String #" + i + " is " + xs(i))
}

কীভাবে আমরা দক্ষতার সাথে পুনরাবৃত্তি করতে পারি এবং ব্যবহার না করেই পারি var ?

আপনি এটি করতে পারে

val xs = Array("first", "second", "third")
val indexed = xs zipWithIndex
for (x <- indexed) println("String #" + x._2 + " is " + x._1)

তবে তালিকাটি দু'বার বিভ্রান্ত হয়েছে - খুব দক্ষ নয়।


এগুলি সব ভাল প্রতিক্রিয়া। জাভা থেকে 'লুপগুলির জন্য আমি কী অনুভব করছি তা হ'ল একাধিক প্রারম্ভিককরণের ক্ষমতা এবং কেবল ইনক্রিমেন্ট / হ্রাসের চেয়ে বেশি ব্যবহার করে "পুনরাবৃত্তি" করার ক্ষমতা। এটি একটি উদাহরণ যেখানে জাভা স্কালার চেয়ে আরও সংক্ষিপ্ত হতে পারে।
তত্পর

... "ইনক্রিট" কেবলমাত্র ইনক্রিমেন্ট / হ্রাসের চেয়ে বেশি ব্যবহার করে ... স্কালায় ধাপে পুনরাবৃত্তি করা সম্ভব হয়, বা লুপ শিরোনামে "if" শর্তে পুনরাবৃত্তি করা সম্ভব। বা আপনি অন্য কিছু খুঁজছেন?
-নাম-মনোনীত

4
/ * জাভা * / এর জন্য (ইনট্রি আমি = 0, জে = 0; আই + জ <100; আই + = জে * 2, জে + = আই +২) {... Sc স্ক্যালায় আপনি কীভাবে এটি 1 লাইনে করতে পারেন?
তত্পর

4
@ স্নেপ্পি: আমার মতে স্কালায় সবচেয়ে প্রাকৃতিক অনুবাদটি একটি whileলুপ হবে। আমার স্মরণ হিসাবে, কয়েক বছর আগে এখানে বিতর্ক হয়েছিল যে স্কালার জাভা for(;;)লুপের উত্তরাধিকারী হওয়া উচিত , এবং সিদ্ধান্ত নেওয়া হয়েছিল যে সুবিধাটি যুক্ত জটিলতাকে ন্যায়সঙ্গত করার পক্ষে যথেষ্ট নয়।
কিপটন ব্যারোস

উত্তর:


132

দু'বার ট্র্যাভারিংয়ের চেয়ে অনেক খারাপ, এটি জোড়াগুলির মধ্যবর্তী অ্যারে তৈরি করে। আপনি ব্যবহার করতে পারেন view। আপনি যখন করেন collection.view, আপনি পরবর্তী কলগুলি পুনরাবৃত্তির সময় অলসভাবে অভিনয় হিসাবে ভাবতে পারেন। আপনি যদি যথাযথভাবে উপলব্ধি করা সংগ্রহটি ফিরে পেতে চান তবে আপনি forceশেষে কল করুন। এখানে এটি অকেজো এবং ব্যয়বহুল হবে। সুতরাং আপনার কোড পরিবর্তন করুন

for((x,i) <- xs.view.zipWithIndex) println("String #" + i + " is " + x)

6
দুর্দান্ত ধারণা, কেবল একটি ট্র্যাভারসাল, তবে এটি নতুন জোড় তৈরি করে, এমনকি যদি এটি একটি নতুন সংগ্রহ সঠিকভাবে তৈরি না করে।
তত্পর

4
বেশ ঠিক। ওয়েল একটি অস্পষ্ট আশা থাকতে পারে যে জেভিএম এই সমস্ত সৃষ্টিকে অপ্টিমাইজ করতে পারে, তবে আমি এটির উপর নির্ভর করব না। আমি এমন কোনও সমাধান দেখতে পাচ্ছি না যা তত্কালীন সূচকগুলিতে পুনরুক্তির উপর ভিত্তি করে না।
দিদিয়ের ডুপন্ট

4
@ स्न্পি এই উত্তরটি বেছে নেওয়া উচিত ছিল! সূচক দ্বারা উপাদানগুলিতে অ্যাক্সেস করা, যা বেশিরভাগ অন্যান্য উত্তরে প্রস্তাবিত হয়েছিল, এটি স্কালার কার্যকরী প্রকৃতির লঙ্ঘন করে এবং লিঙ্কযুক্ত তালিকাগুলিতে (যেমন List, স্কালায় সর্বাধিক ব্যবহৃত সংগ্রহ) তে দুর্দান্তভাবে সম্পাদন করে - এবং কেবল তাদের উপর নয়। এখানেapply অপারেশন পরীক্ষা করে দেখুন । লিঙ্কযুক্ত তালিকার মতো সংগ্রহে সূচী অনুসারে কোনও উপাদানটিতে প্রতিটি অ্যাক্সেস তালিকার একটি ট্র্যাভ্যাসাল ফলাফল in
নিকিতা ভোলকভ

এখানে বেশ কিছু ভিন্ন পদ্ধতির দেখানো হয়েছে: স্ট্যাকওভারফ্লো.com
নীল

কেন এই দক্ষ? এটি একটি নতুন অ্যারে অবজেক্ট তৈরি করছে এবং একটি অতিরিক্ত ফাংশন (`দর্শন ') ব্যবহার করে তাই বুদ্ধিমানভাবে মূর্খতা বোধ না করে কেন এটি বিকাশকারী বা মেশিনের পক্ষে দক্ষ see
ম্যাটানস্টার

70

এটা তোলে উল্লিখিত হয়েছে Scala যে করে জন্য সিনট্যাক্স আছে forলুপ:

for (i <- 0 until xs.length) ...

বা সহজভাবে

for (i <- xs.indices) ...

তবে আপনি দক্ষতাও চেয়েছিলেন। এটা পরিনত হয় যে Scala forসিনট্যাক্স আসলে যেমন উচ্চতর ক্রম পদ্ধতি জন্য অন্বিত চিনি map, foreachইত্যাদি যেমন, কিছু কিছু ক্ষেত্রে এই লুপ অদক্ষ হতে পারে, উদাঃ কিভাবে নিখুত এবং Scala মধ্যে লুপ-comprehensions জন্য?

(সুসংবাদটি হ'ল স্কালার দল এটি উন্নতি করার জন্য কাজ করছে Here বাগ ট্র্যাকারে এই বিষয়টি এখানে রয়েছে: https://issues.scala-lang.org/browse/SI-4633 )

চূড়ান্ত দক্ষতার জন্য, কেউ একটি whileলুপ ব্যবহার করতে পারেন বা, যদি আপনি varলেজ পুনরাবৃত্তিগুলির ব্যবহারগুলি অপসারণ করার জন্য জোর দেন :

import scala.annotation.tailrec

@tailrec def printArray(i: Int, xs: Array[String]) {
  if (i < xs.length) {
    println("String #" + i + " is " + xs(i))
    printArray(i+1, xs)
  }
}
printArray(0, Array("first", "second", "third"))

নোট করুন যে পদ্ধতিটি আসলে টেল রিকার্সিভ তা নিশ্চিত করার জন্য al চ্ছিক @tailrec টীকাটি কার্যকর। স্কালা সংকলকটি সময় লুপগুলির সমতুল্য বাইট কোডে পুচ্ছ-পুনরাবৃত্ত কলগুলি অনুবাদ করে।


ইনডেক্স পদ্ধতি / ফাংশন উল্লেখ করার জন্য +1 হিসাবে আমি এটি কার্য-বাই-ওয়ান প্রোগ্রামিং ত্রুটির পুরো সেটটি অপসারণের কারণে পছন্দনীয় উপায় বলে মনে করি।
বিশৃঙ্খলা

4
এখানে অবশ্যই লক্ষ রাখতে হবে যে যদি xsকোনও ধরণের লিঙ্কযুক্ত তালিকার হয় (যেমন বিস্তৃত ব্যবহৃত List) তবে সূচকের মতো এর উপাদানগুলিতে অ্যাক্সেস xs(i)করা লিনিয়ার হবে এবং সুতরাং এটি for (i <- xs.indices) println(i + " : " + xs(i))সমানের চেয়ে খারাপভাবে সম্পাদন করবে for((x, i) <- xs.zipWithIndex) println(i + " : " + x), কারণ এটি কেবলমাত্র আরও অনেক বেশি ফলাফল করবে ফণা অধীনে দুটি traversals। সুতরাং মতামতগুলি ব্যবহারের পরামর্শ দেওয়ার জন্য @ ডিডিয়ার্ডের উত্তরটি সবচেয়ে সাধারণ এবং সর্বাধিক অভিহিতকারী, আইএমও হিসাবে গ্রহণ করা উচিত।
নিকিতা ভোলকভ

4
যদি সর্বাধিক দক্ষতার প্রয়োজন হয় (উদাহরণস্বরূপ, সংখ্যার কম্পিউটিংয়ে) এটি লিঙ্কযুক্ত তালিকায় প্রবেশের চেয়ে সূচকের অ্যারেগুলির চেয়ে দ্রুত। একটি লিঙ্কযুক্ত তালিকার নোডগুলি পৃথকভাবে গাদা বরাদ্দ করা হয়, এবং বিভিন্ন মেমরির অবস্থানগুলিতে ঝাঁপিয়ে পড়া সিপিইউ ক্যাশে ভাল খেলেন না। যদি একটি viewব্যবহার করা হয় তবে এই এমনকি উচ্চ স্তরের বিমূর্ততা হিপ এবং জিসির উপর আরও চাপ ফেলবে। আমার অভিজ্ঞতায় সংখ্যার কোডে গাদা বরাদ্দ এড়ানোর মাধ্যমে প্রায়শই 10 টি কার্যকারিতা হয়।
কিপটন ব্যারোস

20

আরও একটি উপায়:

scala> val xs = Array("first", "second", "third")
xs: Array[java.lang.String] = Array(first, second, third)

scala> for (i <- xs.indices)
     |   println(i + ": " + xs(i))
0: first
1: second
2: third

4
আমি আপনার সূচকগুলি পদ্ধতি / ফাংশনটি উল্লেখ করতে চাই। এটি জটিলতা হ্রাস করে এবং কার্যত "অফ ​​বাই এক" ত্রুটিগুলির সম্পূর্ণ সেটটি সরিয়ে দেয় যা সমস্ত সফ্টওয়্যার ইঞ্জিনিয়ারিংয়ের মধ্যে সবচেয়ে সাধারণ প্রোগ্রামিং ত্রুটি / বাগ।
বিশৃঙ্খলা

14

আসলে, স্কালায় সূচি সহ পুরানো জাভা-স্টাইলের লুপ রয়েছে:

scala> val xs = Array("first","second","third")
xs: Array[java.lang.String] = Array(first, second, third)

scala> for (i <- 0 until xs.length)
     | println("String # " + i + " is "+ xs(i))

String # 0 is first
String # 1 is second
String # 2 is third

কোথায় 0 until xs.lengthবা 0.until(xs.length)এমন কোনও RichIntপদ্ধতি যা Rangeলুপিংয়ের জন্য উপযুক্ত।

এছাড়াও, আপনি এটি দিয়ে লুপ চেষ্টা করতে পারেন to:

scala> for (i <- 0 to xs.length-1)
     | println("String # " + i + " is "+ xs(i))
String # 0 is first
String # 1 is second
String # 2 is third

4
xs(i)তালিকাগুলিতে ও (এন ^ 2) এর জটিলতা বাড়ায়
ভাদজিম

তা সত্য @Vadzim, কিন্তু যে এছাড়াও আপনি একটি LinkedList সঙ্গে সূচকের উপর লুপ জন্য একটি ব্যবহৃত জাভা কেস হবে
francoisr

4
অ্যারেতে এক্স (আই) এর ক্ষেত্রে উপরের কোডটি ও (এন), তাই না? যেহেতু স্কালায় অ্যারেগুলি প্রায়-ধ্রুবক সময় এলোমেলো অ্যাক্সেসের প্রস্তাব দেয়?
dhfromkorea

4
@ ডিফফ্র্যামকোরিয়া হ্যাঁ, অ্যারেগুলির পক্ষে দ্রুত হওয়া উচিত (সত্যই ও (এন))
ওম-মনোনীত-


4

স্কেলে লুপিং বেশ সহজ। প্রাক্তন জন্য আপনার পছন্দসই কোন অ্যারে তৈরি করুন।

val myArray = new Array[String](3)
myArray(0)="0";
myArray(1)="1";
myArray(2)="2";

লুপের প্রকার,

for(data <- myArray)println(data)

for (i <- 0 until myArray.size)
println(i + ": " + myArray(i))

4

প্রকৃতপক্ষে, zipWithIndexকোনও সংগ্রহকে কল করা এটিকে অতিক্রম করবে এবং জোড়গুলির জন্য একটি নতুন সংগ্রহ তৈরি করবে। এটি এড়াতে, আপনি zipWithIndexসংগ্রহের জন্য কেবল পুনরুক্তিকারীকে কল করতে পারেন । এটি কেবলমাত্র একটি নতুন পুনরাবৃত্তির ফিরিয়ে দেবে যা পুনরাবৃত্তির সময় সূচকের উপর নজর রাখে, সুতরাং অতিরিক্ত সংগ্রহ বা অতিরিক্ত ট্র্যাভারসিং তৈরি না করে।

এই হল কিভাবে scala.collection.Iterator.zipWithIndexবর্তমানে 2.10.3 বাস্তবায়িত হয়:

  def zipWithIndex: Iterator[(A, Int)] = new AbstractIterator[(A, Int)] {
    var idx = 0
    def hasNext = self.hasNext
    def next = {
      val ret = (self.next, idx)
      idx += 1
      ret
    }
  }

এটি সংগ্রহে ভিউ তৈরির চেয়ে কিছুটা বেশি দক্ষ হওয়া উচিত।


3

স্টাডলিবের এমন কিছুই নেই যা টুপল আবর্জনা তৈরি না করে এটি আপনার পক্ষে করবে, তবে এটি নিজের লেখা খুব বেশি কঠিন নয়। দুর্ভাগ্যক্রমে আমি কখনই উপযুক্ত ক্যানবিল্ড থেকে এই জাতীয় জিনিসগুলিকে সংগ্রহ করার ধরণের ক্ষেত্রে জেনেরিক তৈরি করার জন্য অন্তর্নিহিত অপ্রতুলতা কীভাবে করা যায় তা বোঝার মাথা ঘামাইনি, তবে যদি এটি সম্ভব হয় তবে আমি নিশ্চিত যে কেউ আমাদের আলোকিত করবেন। :)

def foreachWithIndex[A](as: Traversable[A])(f: (Int,A) => Unit) {
  var i = 0
  for (a <- as) {
    f(i, a)
    i += 1
  }
}

def mapWithIndex[A,B](in: List[A])(f: (Int,A) => B): List[B] = {
  def mapWithIndex0(in: List[A], gotSoFar: List[B], i: Int): List[B] = {
    in match {
      case Nil         => gotSoFar.reverse
      case one :: more => mapWithIndex0(more, f(i, one) :: gotSoFar, i+1)
    }
  }
  mapWithIndex0(in, Nil, 0)
}

// Tests....

@Test
def testForeachWithIndex() {
  var out = List[Int]()
  ScalaUtils.foreachWithIndex(List(1,2,3,4)) { (i, num) =>
    out :+= i * num
  }
  assertEquals(List(0,2,6,12),out)
}

@Test
def testMapWithIndex() {
  val out = ScalaUtils.mapWithIndex(List(4,3,2,1)) { (i, num) =>
    i * num
  }

  assertEquals(List(0,3,4,3),out)
}

এটি এমন একটি বিষয় যা নিশ্চিতভাবে স্ট্যান্ডার্ড লাইব্রেরিতে যুক্ত হবে sense
তত্পর

4
আমি এতটা নিশ্চিত নই, যেহেতু আপনি যদি সাধারণ ফোরচ / মানচিত্রের এপিআই অনুসারে চান তবে আপনি যেভাবেই টুপলসের সাথে আটকে আছেন।
অ্যালেক্স ক্রুজ

3

পুনরাবৃত্তি করার আরও কয়েকটি উপায়:

scala>  xs.foreach (println) 
first
second
third

ভবিষ্যদ্বাণী, এবং অনুরূপ, মানচিত্র, যা কিছু ফেরত দেবে (ফাংশনের ফলাফল যা মুদ্রণের জন্য, ইউনিট, সুতরাং ইউনিটের একটি তালিকা)

scala> val lens = for (x <- xs) yield (x.length) 
lens: Array[Int] = Array(5, 6, 5)

সূচকের সাথে নয়, উপাদানগুলির সাথে কাজ করুন

scala> ("" /: xs) (_ + _) 
res21: java.lang.String = firstsecondthird

ভাঁজ

for(int i=0, j=0; i+j<100; i+=j*2, j+=i+2) {...}

পুনরাবৃত্তি দিয়ে করা যেতে পারে:

def ijIter (i: Int = 0, j: Int = 0, carry: Int = 0) : Int =
  if (i + j >= 100) carry else 
    ijIter (i+2*j, j+i+2, carry / 3 + 2 * i - 4 * j + 10) 

বহনকারী অংশটি কেবলমাত্র উদাহরণ এবং i এবং j এর সাথে কিছু করা। এটি কোন ইন্টি হতে হবে না।

সহজ স্টাফ জন্য, লুপ জন্য স্বাভাবিক কাছাকাছি:

scala> (1 until 4)
res43: scala.collection.immutable.Range with scala.collection.immutable.Range.ByOne = Range(1, 2, 3)

scala> (0 to 8 by 2)   
res44: scala.collection.immutable.Range = Range(0, 2, 4, 6, 8)

scala> (26 to 13 by -3)
res45: scala.collection.immutable.Range = Range(26, 23, 20, 17, 14)

বা আদেশ ছাড়াই:

List (1, 3, 2, 5, 9, 7).foreach (print) 

3

আমি নিম্নলিখিত পন্থাগুলি আছে

object HelloV2 {

   def main(args: Array[String]) {

     //Efficient iteration with index in Scala

     //Approach #1
     var msg = "";

     for (i <- args.indices)
     {
       msg+=(args(i));
     }
     var msg1="";

     //Approach #2
     for (i <- 0 until args.length) 
     {
       msg1 += (args(i));
     }

     //Approach #3
     var msg3=""
     args.foreach{
       arg =>
        msg3 += (arg)
     }


      println("msg= " + msg);

      println("msg1= " + msg1);

      println("msg3= " + msg3);

   }
}


0

প্রস্তাবিত সমাধানগুলি সত্য হয় যে তারা স্পষ্টভাবে কোনও সংগ্রহের উপর পুনরাবৃত্তি করে বা সংগ্রহটিকে কোনও কার্যক্রমে স্টাফ করে। স্কালার স্বাভাবিক প্রতিচ্ছবিগুলির সাথে লেগে থাকা এবং সূচিটি স্বাভাবিক মানচিত্রের মধ্যে রাখা - বা ফোরচ-পদ্ধতিগুলির মধ্যে। এটি মেমোজাইজিং ব্যবহার করে করা যেতে পারে। ফলস্বরূপ কোডটি দেখতে পারে

myIterable map (doIndexed(someFunction))

এই উদ্দেশ্য অর্জনের জন্য এখানে একটি উপায়। নিম্নলিখিত ইউটিলিটি বিবেচনা করুন:

object TraversableUtil {
    class IndexMemoizingFunction[A, B](f: (Int, A) => B) extends Function1[A, B] {
        private var index = 0
        override def apply(a: A): B = {
            val ret = f(index, a)
            index += 1
            ret
        }
    }

    def doIndexed[A, B](f: (Int, A) => B): A => B = {
        new IndexMemoizingFunction(f)
    }
}

আপনার যা প্রয়োজন তা এটি ইতিমধ্যে। আপনি উদাহরণস্বরূপ এটি প্রয়োগ করতে পারেন:

import TraversableUtil._
List('a','b','c').map(doIndexed((i, char) => char + i))

তালিকার ফলাফল যা

List(97, 99, 101)

এইভাবে, আপনি আপনার কার্যকর ফাংশন মোড়ানো ব্যয় করে স্বাভাবিক ট্র্যাভারেবল-ফাংশন ব্যবহার করতে পারেন। উপভোগ করুন!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.