Как я могу использовать карту и получать индекс, а также в Scala?

Есть ли встроенный модуль List/Sequence, который ведет себя как map и также предоставляет индекс элемента?

Ответ 1

Я считаю, что вы ищете 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

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

У вас также есть такие варианты, как:

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

или

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

Ответ 2

Используйте карту. zipWithIndex

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

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

Результат:

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

Ответ 3

Предлагаемые решения связаны с тем, что они создают промежуточные коллекции или вводят переменные, которые не являются строго необходимыми. В конечном счете все, что вам нужно сделать, это отслеживать количество шагов итерации. Это можно сделать с помощью memoizing. Полученный код может выглядеть как

myIterable map (doIndexed(someFunction))

doIndexed -Funk обертывает внутреннюю функцию, которая получает как индекс, так и элементы myIterable. Это может быть вам знакомо с JavaScript.

Вот способ достижения этой цели. Рассмотрим следующую утилиту:

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)

Таким образом, вы можете использовать обычные функции Traversable за счет переноса вашей эффективной функции. Накладные расходы - это создание memoizing объекта и счетчика в нем. В противном случае это решение будет таким же хорошим (или плохим) с точки зрения памяти или производительности, как использование unindexed map. Наслаждайтесь!

Ответ 4

В 2.7.x есть CountedIterator (который вы можете получить из обычного итератора с .counted). Я считаю, что он был устаревшим (или просто удаленным) в 2,8, но он достаточно прост в сворачивании. Вы должны иметь возможность назвать итератор:

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)

Ответ 5

Или, если ваша коллекция имеет постоянное время доступа, вы можете сопоставить список индексов вместо фактической коллекции:

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

Ответ 6

Используйте .map в .zipWithIndex со структурой данных карты.

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

Результаты

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

Ответ 7

Если вам также требуется поиск по значениям карты (как я и делал):

val ls = List("a","b","c")
val ls_index_map = ls.zipWithIndex.toMap 

Ответ 8

Есть два способа сделать это.

ZipWithIndex: Создает счетчик, автоматически начинающийся с 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")
  }

Вывод обоих кодов будет следующим:

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

Zip: используйте метод zip с Stream для создания счетчика. Это дает вам возможность контролировать начальное значение.

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

Результат:

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