Scala'da haritayı nasıl kullanabilirim ve bir indeks alabilirim?


99

mapÖğenin dizinine benzer davranan ve aynı zamanda bunu sağlayan yerleşik bir Liste / Sıra var mı ?

Yanıtlar:


148

ZipWithIndex'i aradığına inanıyorum?

scala> val ls = List("Mary", "had", "a", "little", "lamb")
scala> ls.zipWithIndex.foreach{ case (e, i) => println(i+" "+e) }
0 Mary
1 had
2 a
3 little
4 lamb

Kimden: http://www.artima.com/forums/flat.jsp?forum=283&thread=243570

Ayrıca aşağıdaki gibi varyasyonlarınız var:

for((e,i) <- List("Mary", "had", "a", "little", "lamb").zipWithIndex) println(i+" "+e)

veya:

List("Mary", "had", "a", "little", "lamb").zipWithIndex.foreach( (t) => println(t._2+" "+t._1) )

4
zipWithIndexBir döngü / harita / her neyse, indeksi elde etmek için yöntemi kullanmayı kastettim .
ziggystar

Örneğin while, muhtemelen en hızlı seçeneklerden biri olan bir döngü ile karşılaştırma .
ziggystar

Bir Dizi ve bir while döngüsü muhtemelen olabildiğince hızlıdır.
Viktor Klang

2
@ziggystar Performans arıyorsanız, biraz değişmezlikten vazgeçmelisiniz. ZipWithIndex işlevinin içine bakın. Yeni bir çift koleksiyonu oluşturmak için yalnızca bir var kullanır. Java'da yaptığınız gibi, yeni koleksiyonu oluşturmadan bir varlıkları artırmanın aynı yöntemini kullanabilirsiniz. Ama işlevsel bir tarz değil. Gerçekten ihtiyacınız olup olmadığını düşünün.
Cristian Vrabie

Görünüşe göre zipWithIndex'in kendisi bile işlevsel bir stil değil. Her neyse, viewsizi kullanmanın fazladan bir Liste oluşturmayı ve geçişi engelleyebileceğinden bahsetmek gerektiğini düşünüyorum .
herman

56

Kullanın. harita içinde. zipWithIndex

val myList = List("a", "b", "c")

myList.zipWithIndex.map { case (element, index) => 
   println(element, index) 
   s"${element}(${index})"
}

Sonuç:

List("a(0)", "b(1)", "c(2)")

11
Bu, mapyalnızca bir .net dosyasında yazdırmak yerine istendiği gibi a kullanan gördüğüm ilk iyi örnek foreach.
Greg Chabala

10

Önerilen çözümler, ara koleksiyonlar oluşturdukları veya kesinlikle gerekli olmayan değişkenler getirdikleri gerçeğinden muzdariptir. Nihayetinde yapmanız gereken tek şey, bir yinelemenin adım sayısını takip etmektir. Bu, hafızaya alma kullanılarak yapılabilir. Ortaya çıkan kod şöyle görünebilir:

myIterable map (doIndexed(someFunction))

doIndexedFonksiyonlu bir dizin, bir elemanlarını hem alır hem de iç fonksiyonu sarar myIterable. Bu size JavaScript'ten tanıdık gelebilir.

İşte bu amaca ulaşmanın bir yolu. Aşağıdaki yardımcı programı düşünün:

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)
    }
}

Zaten ihtiyacınız olan tek şey bu. Bunu örneğin aşağıdaki gibi uygulayabilirsiniz:

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

listede hangi sonuç

List(97, 99, 101)

Bu şekilde, etkin işlevinizi sarma pahasına olağan Traversable işlevlerini kullanabilirsiniz. Ek yük, hafızaya alma nesnesinin ve içindeki sayacın yaratılmasıdır. Aksi takdirde bu çözüm, bellek veya performans açısından indekslenmemiş kullanmak kadar iyidir (veya kötü) map. Zevk almak!


1
Bu, soruna çok zarif bir çözümdür. Geçici bir koleksiyon oluşturmamak için +1. Paralel bir koleksiyonda çalışmayacak, ancak yine de çok güzel bir çözüm.
fbl

5
Geçici bir koleksiyon oluşturmak istemiyorsanız, coll.view.zipWithIndexbunun yerine kullanıncoll.zipWithIndex
tsuna

5

Orada CountedIterator(.counted ile normal bir yineleyici almak olabilir) 2.7.x içinde. 2.8'de kullanımdan kaldırıldığına (veya basitçe kaldırıldığına) inanıyorum, ancak kendi oyununuzu döndürmek yeterince kolay. Yineleyiciyi adlandırabilmeniz gerekir:

val ci = List("These","are","words").elements.counted
scala> ci map (i => i+"=#"+ci.count) toList
res0: List[java.lang.String] = List(These=#0,are=#1,words=#2)

3

Veya koleksiyonunuzun sürekli erişim süresine sahip olduğunu varsayarak, gerçek koleksiyon yerine dizin listesini eşleyebilirsiniz:

val ls = List("a","b","c")
0.until(ls.length).map( i => doStuffWithElem(i,ls(i)) )

1
Bunu yapmanın daha zarif bir yolu basitçe: ls.indices.map(i => doStuffWithElem(i, ls(i))
Assil Ksiksi

3
@aksiksi Pekala, bunun hemen hemen aynı şey indicesolduğu için uygulandığını0 until length görmek : P
Cristian Vrabie

1
karmaşıklık nedeniyle olumsuz oy - ls (i) ile yineleme O (n ^ 2) alır
Moshe Bixenshpaner

1
@MosheBixenshpaner Yeterince adil. Benim örnek Listgerçekten zayıftı. Bununla birlikte, koleksiyonunuzun sürekli erişim süresine sahip olması durumunda bunun uygun olduğunu belirttim. Seçmeliydin Array.
Cristian Vrabie

1

Kullanım .map içinde .zipWithIndex Harita verileri yapısıyla

val sampleMap = Map("a" -> "hello", "b" -> "world", "c" -> "again")

val result = sampleMap.zipWithIndex.map { case ((key, value), index) => 
    s"Key: $key - Value: $value with Index: $index"
}

Sonuçlar

 List(
       Key: a - Value: hello with Index: 0, 
       Key: b - Value: world with Index: 1, 
       Key: c - Value: again with Index: 2
     )

1

Bunu yapmanın iki yolu var.

ZipWithIndex: Otomatik olarak 0 ile başlayan bir sayaç oluşturur.

  // zipWithIndex with a map.
  val days = List("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
  days.zipWithIndex.map {
        case (day, count) => println(s"$count is $day")
  }
  // Or use it simply with a for.
  for ((day, count) <- days.zipWithIndex) {
        println(s"$count is $day")
  }

Her iki kodun çıktısı şu şekilde olacaktır:

0 is Sun
1 is Mon
2 is Tue
3 is Wed
4 is Thu
5 is Fri
6 is Sat

Zip : Sayaç oluşturmak için bir Akış ile zip yöntemini kullanın. Bu size başlangıç ​​değerini kontrol etmenin bir yolunu verir.

for ((day, count) <- days.zip(Stream from 1)) {
  println(s"$count is $day")
}

Sonuç:

1 is Sun
2 is Mon
3 is Tue
4 is Wed
5 is Thu
6 is Fri
7 is Sat

0

Harita değerlerini de aramanız gerekiyorsa (benim zorunda olduğum gibi):

val ls = List("a","b","c")
val ls_index_map = ls.zipWithIndex.toMap 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.