valores una repetidos registros quitar para los lista hoja folios extraer elimine eliminar elementos duplicados datos código cálculo contar con como campo buscar articulosdescuento archivos scala

scala - una - formula para buscar datos repetidos en excel



¿Cómo eliminar 2 o más duplicados de la lista y mantener su orden inicial? (13)

Aquí está el código canónico de Scala para reducir tres o más en una fila a dos en una fila:

def checkForTwo(candidate: List[Int]): List[Int] = { candidate match { case x :: y :: z :: tail if x == y && y == z => checkForTwo(y :: z :: tail) case x :: tail => x :: checkForTwo(tail) case Nil => Nil } }

Observa los primeros tres elementos de la lista y, si son iguales, elimina el primero y repite el proceso. De lo contrario, pasa elementos a través.

Asumamos que tenemos una lista de Scala:

val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)

Podemos eliminar fácilmente los duplicados utilizando el siguiente código:

l1.distinct

o

l1.toSet.toList

Pero, ¿qué pasa si queremos eliminar duplicados solo si hay más de 2? Entonces, si hay más de 2 elementos con el mismo valor, solo quedamos dos y eliminamos el resto.

Pude lograrlo con el siguiente código:

l1.groupBy(identity).mapValues(_.take(2)).values.toList.flatten

Eso me dio el resultado:

List(2, 2, 5, 1, 1, 3, 3)

Los elementos se eliminan, pero el orden de los elementos restantes es diferente de cómo aparecieron estos elementos en la lista inicial. ¿Cómo hacer esta operación y seguir siendo el orden de la lista original?

Entonces el resultado para l1 debería ser:

List(1, 2, 3, 1, 3, 2, 5)


Aquí hay una solución recursiva (se acumulará el desbordamiento de listas grandes):

def filterAfter[T](l: List[T], max: Int): List[T] = { require(max > 1) //keep the state of seen values val seen = Map[T, Int]().withDefaultValue(0)//init to 0 def filterAfter(l: List[T], seen: Map[T, Int]): (List[T], Map[T, Int]) = { l match { case x :: xs => if (seen(x) < max) { //Update the state and pass to next val pair = filterAfter(xs, seen updated (x, seen(x) + 1)) (x::pair._1, pair._2) } else { //already seen more than max filterAfter(xs, seen) } case _ => (l, seen)//empty, terminate recursion } } //call inner recursive function filterAfter(l, seen, 2)._1 }


Basado en la respuesta de experquisite, pero usando foldLeft :

def noMoreThanBis(xs: List[Int], max: Int) = { val initialState: (Map[Int, Int], List[Int]) = (Map().withDefaultValue(0), Nil) val (_, result) = xs.foldLeft(initialState) { case ((count, res), x) => if (count(x) >= max) (count, res) else (count.updated(x, count(x) + 1), x :: res) } result.reverse }


De manera similar a como se implementa distinto, con un conjunto múltiple en lugar de un conjunto:

def noMoreThan[T](list : List[T], max : Int) = { val b = List.newBuilder[T] val seen = collection.mutable.Map[T,Int]().withDefaultValue(0) for (x <- list) { if (seen(x) < max) { b += x seen(x) += 1 } } b.result() }


Es un poco feo, pero es relativamente rápido

val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1) l1.foldLeft((Map[Int, Int](), List[Int]())) { case ((m, ls), x) => { val z = m + ((x, m.getOrElse(x, 0) + 1)) (z, if (z(x) <= 2) x :: ls else ls) }}._2.reverse

Da: List(1, 2, 3, 1, 3, 2, 5)


Mi humilde respuesta:

def distinctOrder[A](x:List[A]):List[A] = { @scala.annotation.tailrec def distinctOrderRec(list: List[A], covered: List[A]): List[A] = { (list, covered) match { case (Nil, _) => covered.reverse case (lst, c) if c.count(_ == lst.head) >= 2 => distinctOrderRec(list.tail, covered) case _ => distinctOrderRec(list.tail, list.head :: covered) } } distinctOrderRec(x, Nil) }

Con los resultados:

scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1) l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1) scala> distinctOrder(l1) res1: List[Int] = List(1, 2, 3, 1, 3, 2, 5)

En la Edición: ¡Justo antes de irme a la cama, se me ocurrió esto!

l1.foldLeft(List[Int]())((total, next) => if (total.count(_ == next) >= 2) total else total :+ next)

Con una respuesta de:

res9: List[Int] = List(1, 2, 3, 1, 3, 2, 5)


No es el más eficiente.

scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1) l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1) scala> l1.zipWithIndex.groupBy( _._1 ).map(_._2.take(2)).flatten.toList.sortBy(_._2).unzip._1 res10: List[Int] = List(1, 2, 3, 1, 3, 2, 5)


No es la más bonita. Espero ver las otras soluciones.

def noMoreThan(xs: List[Int], max: Int) = { def op(m: Map[Int, Int], a: Int) = { m updated (a, m(a) + 1) } xs.scanLeft( Map[Int,Int]().withDefaultValue(0) ) (op).tail .zip(xs) .filter{ case (m, a) => m(a) <= max } .map(_._2) } scala> noMoreThan(l1, 2) res0: List[Int] = List(1, 2, 3, 1, 3, 2, 5)


Prefiero acercarme con Map inmutable:

def noMoreThan[T](list: List[T], max: Int): List[T] = { def go(tail: List[T], freq: Map[T, Int]): List[T] = { tail match { case h :: t => if (freq(h) < max) h :: go(t, freq + (h -> (freq(h) + 1))) else go(t, freq) case _ => Nil } } go(list, Map[T, Int]().withDefaultValue(0)) }


Qué tal esto:

list .zipWithIndex .groupBy(_._1) .toSeq .flatMap { _._2.take(2) } .sortBy(_._2) .map(_._1)


Solución con groupBy y filter, sin ningún tipo de clasificación (por lo que es O (N), la clasificación le dará O (Nlog (N)) adicional en un caso típico):

val li = l1.zipWithIndex val pred = li.groupBy(_._1).flatMap(_._2.lift(1)) //1 is your "2", but - 1 for ((x, i) <- li if !pred.get(x).exists(_ < i)) yield x


Versión más sencilla utilizando foldLeft:

l1.foldLeft(List[Int]()){(acc, el) => if (acc.count(_ == el) >= 2) acc else el::acc}.reverse


distinct se define para SeqLike como

/** Builds a new $coll from this $coll without any duplicate elements. * $willNotTerminateInf * * @return A new $coll which contains the first occurrence of every element of this $coll. */ def distinct: Repr = { val b = newBuilder val seen = mutable.HashSet[A]() for (x <- this) { if (!seen(x)) { b += x seen += x } } b.result() }

Podemos definir nuestra función de manera muy similar:

def distinct2[A](ls: List[A]): List[A] = { val b = List.newBuilder[A] val seen1 = mutable.HashSet[A]() val seen2 = mutable.HashSet[A]() for (x <- ls) { if (!seen2(x)) { b += x if (!seen1(x)) { seen1 += x } else { seen2 += x } } } b.result() } scala> distinct2(l1) res4: List[Int] = List(1, 2, 3, 1, 3, 2, 5)

Esta versión usa el estado interno, pero sigue siendo puro. También es bastante fácil generalizar para n arbitraria (actualmente 2), pero la versión específica es más eficaz.

Puede implementar la misma función con los pliegues que llevan el estado "lo que se ve una y dos veces" con usted. Sin embargo, el bucle for y el estado mutable hacen el mismo trabajo.