web-dev-qa-db-fra.com

Comment supprimer un élément d'une liste dans Scala n'ayant que son index?

J'ai une liste comme suit:

val internalIdList: List[Int] = List()

internalIdList = List(11, 12, 13, 14, 15)

Dans cette liste supprimerait le troisième élément afin d'obtenir:

internalIdList = List(11, 12, 14, 15)

Je ne peux pas utiliser un ListBuffer, suis obligé de maintenir la structure existante. Comment puis-je faire?

Merci à tous

14
YoBre

Si vous savez que vous allez supprimer le troisième élément (index 2), vous pouvez simplement utiliser

val trunced = internalIdList.take(2) ++ internalIdList.drop(3)

sinon, si vous ne savez pas à l'avance quel sera l'index de l'élément à supprimer, vous pouvez écrire une fonction comme celle-ci:

def removeIndex(ix: Int) = if (internalIdList.size < ix) internalIdList
                           else internalIdList.take(ix) ++ internalIdList.drop(ix+1)
13
Shadowlands

Il y a une méthode .patch sur Seq, donc pour supprimer le troisième élément, vous pouvez simplement faire ceci:

List(11, 12, 13, 14, 15).patch(2, Nil, 1)

Qui dit: À partir de l'index 2 , supprimez 1 et remplacez-le par Nil .

Connaître cette méthode en profondeur vous permet de faire beaucoup plus que cela. Vous pouvez échanger n'importe quelle sous-liste d'une liste avec d'autres arbitraires.

38
Rok Kralj

Une façon idiomatique de le faire consiste à compresser la valeur avec leur index, à filtrer, puis à projeter à nouveau la valeur:

scala> List(11,12,13,14,15).zipWithIndex.filter(_._2 != 2).map(_._1)
res0: List[Int] = List(11, 12, 14, 15)

Mais vous pouvez aussi utiliser splitAt:

scala> val (x,y) = List(11,12,13,14,15).splitAt(2)
x: List[Int] = List(11, 12)
y: List[Int] = List(13, 14, 15)

scala> x ++ y.tail
res5: List[Int] = List(11, 12, 14, 15)
10
Nicolas

Si vous insistez pour utiliser la méthode oldschool, utilisez collect:

List(1,2,3,4).zipWithIndex.collect { case (a, i) if i != 2 => a }

Cependant, je préfère toujours la méthode dans mon autre réponse.

1
Rok Kralj
(internalIdList.indices.collect { case i if i != 3 => internalList(i) }).toList

Pour généraliser cela ...

def removeIndex[A](s: Seq[A], n: Int): Seq[A] = s.indices.collect { case i if i != n => s(i) }

Bien que cela renvoie souvent un vecteur, vous devez donc le faire.

val otherList = removeIndex(internalIdList, 3).toList

Si vous vouliez vraiment une liste de retour.

Shadowlands a une solution qui tend à être plus rapide pour les séquences linéaires. Celui-ci sera plus rapide avec les séquences indexées.

1
itsbruce

Une fonction générique qui implémente la première solution de Nicolas:

def dropIndex[T](list: List[T], idx: Int): List[T] =
  list.zipWithIndex.filter(_._2 != idx).map(_._1)

Usage:

scala> val letters = List('a', 'b', 'c')
scala> for (i <- 0 until letters.length) println(dropIndex(letters, i))
List(b, c)
List(a, c)
List(a, b)
0
simleo

Utiliser un pour la compréhension sur une liste xs comme ceci,

for (i <- 0 until xs.size if i != nth-1) yield xs(i)

Envisagez également un ensemble d'indices d'exclusion, par exemple val excl = Set(2,4) pour exclure les deuxième et quatrième éléments; par conséquent, nous collectons les éléments dont les indices n'appartiennent pas à l'ensemble d'exclusions, à savoir 

for (i <- 0 until xs.size if !excl(i)) yield xs(i)
0
elm