Làm cách nào tôi có thể sử dụng bản đồ và nhận chỉ mục cũng như trong Scala?


Câu trả lời:


148

Tôi tin rằng bạn đang tìm kiếm zipWithIndex?

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

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

Bạn cũng có các biến thể như:

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

hoặc là:

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

4
Ý tôi là sử dụng zipWithIndexphương thức để lấy chỉ mục bên trong vòng lặp / bản đồ / bất cứ thứ gì.
ziggystar

Ví dụ so sánh với một whilevòng lặp, có lẽ là một trong những lựa chọn nhanh nhất.
ziggystar

Một Array và một vòng lặp while có thể nhanh nhất có thể.
Viktor Klang

2
@ziggystar Nếu bạn đang tìm kiếm hiệu suất, bạn cần đánh đổi một số tính bất biến. Nhìn vào bên trong hàm zipWithIndex. Nó chỉ sử dụng một var để xây dựng một bộ sưu tập các cặp mới. Bạn có thể sử dụng cùng một phương pháp tăng var mà không cần xây dựng bộ sưu tập mới, giống như cách bạn làm trong Java. Nhưng nó không phải là phong cách chức năng. Hãy suy nghĩ nếu bạn thực sự cần nó.
Cristian Vrabie

Vì vậy, có vẻ như ngay cả bản thân zipWithIndex cũng không phải là phong cách chức năng. Dù sao, tôi nghĩ rằng cần phải đề cập rằng việc sử dụng viewbạn sẽ có thể ngăn việc tạo và duyệt qua một Danh sách bổ sung.
herman

55

Sử dụng . bản đồ trong. zipWithIndex

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

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

Kết quả:

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

11
Đây là ví dụ phong phú đầu tiên mà tôi thấy đã sử dụng một maptheo yêu cầu thay vì chỉ in bên trong a foreach.
Greg Chabala

10

Các giải pháp được đề xuất gặp phải thực tế là chúng tạo ra các tập hợp trung gian hoặc giới thiệu các biến không hoàn toàn cần thiết. Cuối cùng, tất cả những gì bạn cần làm là theo dõi số bước của một lần lặp. Điều này có thể được thực hiện bằng cách sử dụng ghi nhớ. Mã kết quả có thể trông giống như

myIterable map (doIndexed(someFunction))

Các doIndexed-Function kết thúc tốt đẹp các chức năng bên trong mà nhận được cả một chỉ số một các yếu tố của myIterable. Điều này có thể quen thuộc với bạn từ JavaScript.

Đây là một cách để đạt được mục đích này. Hãy xem xét tiện ích sau:

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

Đây đã là tất cả những gì bạn cần. Bạn có thể áp dụng điều này ví dụ như sau:

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

kết quả nào trong danh sách

List(97, 99, 101)

Bằng cách này, bạn có thể sử dụng các chức năng Traversable thông thường với chi phí đóng gói chức năng hiệu quả của bạn. Chi phí là việc tạo ra đối tượng ghi nhớ và bộ đếm trong đó. Nếu không, giải pháp này tốt (hoặc xấu) về bộ nhớ hoặc hiệu suất như sử dụng unindexed map. Thưởng thức!


1
Đây là một giải pháp rất thanh lịch cho vấn đề. +1 vì không tạo bộ sưu tập tạm thời. Sẽ không hoạt động trong một bộ sưu tập song song, nhưng vẫn là một giải pháp rất hay.
fbl 14/09/12

5
Nếu bạn không muốn tạo ra một bộ sưu tập tạm thời, chỉ cần sử dụng coll.view.zipWithIndexthay vìcoll.zipWithIndex
tsuna

5

CountedIteratortrong 2.7.x (mà bạn có thể lấy từ một trình lặp bình thường với .counted). Tôi tin rằng nó đã không được dùng nữa (hoặc chỉ đơn giản là bị loại bỏ) trong 2.8, nhưng nó đủ dễ dàng để cuộn của riêng bạn. Bạn cần có thể đặt tên cho trình lặp:

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

Hoặc giả sử bộ sưu tập của bạn có thời gian truy cập không đổi, bạn có thể ánh xạ danh sách chỉ mục thay vì bộ sưu tập thực tế:

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

1
Một cách đơn giản hơn để làm điều này là: ls.indices.map(i => doStuffWithElem(i, ls(i))
Assil Ksiksi

3
@aksiksi Chà, thấy vậy indices được thực hiện như0 until length đó là khá nhiều điều tương tự: P
Cristian Vrabie

1
phản đối vì độ phức tạp - lặp với ls (i) sẽ mất O (n ^ 2)
Moshe Bixenshpaner

1
@MosheBixenshpaner Đủ công bằng. Ví dụ của tôi Listthực sự là nghèo. Tuy nhiên, tôi đã đề cập rằng điều này phù hợp nếu bộ sưu tập của bạn có thời gian truy cập liên tục. Nên đã chọn Array.
Cristian Vrabie,

1

Sử dụng .map trong .zipWithIndex với cấu trúc dữ liệu Bản đồ

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

Các kết quả

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

1

Có hai cách để làm điều này.

ZipWithIndex: Tạo bộ đếm tự động bắt đầu bằng 0.

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

Đầu ra của cả hai mã sẽ là:

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

Zip : Sử dụng phương pháp zip với Luồng để tạo bộ đếm. Điều này cung cấp cho bạn một cách để kiểm soát giá trị bắt đầu.

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

Kết quả:

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

0

Nếu bạn cũng yêu cầu tìm kiếm các giá trị bản đồ (như tôi đã phải làm):

val ls = List("a","b","c")
val ls_index_map = ls.zipWithIndex.toMap 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.