How can I remove all occurrences of a sublist from a list, eg
List(1, 2, 3, 4, 5, 6, 7, 4, 8, 9, 10, 5).removeSubList(4, 5)
should remove all occurrences of (4, 5) (in this order!), so it returns
List(1, 2, 3, 6, 7, 4, 8, 9, 10, 5)
A recursive solution using indexOfSlice:
def removeSubList(l: List[Int], sublist: List[Int]): List[Int] = l.indexOfSlice(sublist) match {
case -1 => l
case index => removeSubList(l.patch(index, Nil, sublist.length), sublist)
}
// all of these print List(1 ,2 ,3):
println(removeSubList(List(1,2,3), List(4,5)))
println(removeSubList(List(1,2,3,4,5), List(4,5)))
println(removeSubList(List(4,5,1,2,3), List(4,5)))
println(removeSubList(List(4,5,1,2,4,5,3), List(4,5)))
EDITED:
(thanks #corvus_192) reverting to using indexOfSlice version instead of using diff, which ignores sublist order.
(thanks #The Archetypal Paul) using patch for cleaner removal of sublist
Using Tzach Zohar idea with different implementation:
def removeSubList[T](list: List[T], sublist: List[T]): List[T] =
if (list.containsSlice(sublist))
removeSubList(list.diff(sublist), sublist)
else list
Variant on Tzach Zohar idea but with the assumption the OP wants a result that does not include the given sublist ever. Handles the case when sublist is empty
/**
* Return `s` with no occurrence of `target` present
*
* #param s
* #param target
* #return The sequence free of any occurrence of the target slice
*/
def removeCompletely[E](s: Seq[E], target: Seq[E]): Seq[E] = {
if (s.isEmpty || target.isEmpty)
s
else
removeCompletely0(s, target)
}
private def removeCompletely0[E](s: Seq[E], target: Seq[E]): Seq[E] = {
val sliceIdx = s.indexOfSlice(target)
if (sliceIdx >= 0) {
val patched = s.patch(sliceIdx, s take 0, target.size)
removeCompletely0(patched, target)
}
else {
s
}
}
Related
I have multiple lists of integers.
val firstList: ArrayList<Int> = arrayListOf(1, 1, 1, 2, 3, 4)
val secondList: ArrayList<Int> = arrayListOf(1, 4, 5, 6, 6, 6, 7, 8)
val thirdList: ArrayList<Int> = arrayListOf(1, 6, 9)
...
I need to remove duplicates only among the other lists, and not within a list itself.
The result should be:
[1,1,1,2,3,4,5,6,6,6,7,8,9]
What is the best approach to do so in Kotlin?
We can filter the additional lists with a .filter and .contains, then add the result to the firstList. Not sure if this is the most efficient way, but it should work.
val firstList: ArrayList<Int> = arrayListOf(1, 1, 1, 2, 3, 4)
val secondList: ArrayList<Int> = arrayListOf(1, 4, 5, 6, 6, 6, 7, 8)
val thirdList: ArrayList<Int> = arrayListOf(1, 6, 9)
firstList += secondList.filterNot { firstList.contains(it) }
firstList += thirdList.filterNot { firstList.contains(it) }
firstList.sort() //not sure if you want the firstList to be sorted or not
You could also make it an extension function, so then it is easier to call.
fun <T> MutableCollection<T>.addOtherNoDuplicates(vararg others: Iterable<T>){
others.forEach {other ->
this += other.filterNot { this.contains(it) }
}
}
Then the call would just be:
firstList.addOtherNoDuplicates(secondList, thirdList) //add as many as you want
firstList.sort()
If you only want to use it for ArrayList, then you can replace the MutableCollection<T> with ArrayList<T> and use the sort() directly in the function itself.
If these are very long lists, you can use a MutableSet on the side to efficiently avoid adding the unwanted values.
val input = listOf(firstList, secondList, thirdList)
val allValues = mutableSetOf<Int>()
val result = mutableListOf<Int>()
for (list in input) {
val newValues = list.filterNot { it in allValues }
result.addAll(newValues)
allValues.addAll(newValues)
}
println(result)
I have a list that can have certain numbers before an index that I don't need. For example:
val tempList: List[Any] = List(0,0,0,0,0,3,.,5,0,2,5)
How would I be able to remove all of the 0's before 3 without filtering out the 0 after the 3?
You can use dropWhile. Suppose you want to remove everything before 1:
scala> val l = List(0, 0, 0, 0, 1, 2, 0)
l: List[Int] = List(0, 0, 0, 0, 1, 2, 0)
scala> l.dropWhile(_ == 0)
res1: List[Int] = List(1, 2, 0)
What you need to do is a twist on dropWhile, that I would call filterWhile.
One simple solution that leverages the Collection API is the following:
def filterWhile[A](
list: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): List[A] = {
val (toFilter, unfiltered) = list.span(whileP)
toFilter.filter(filterP) ++ unfiltered
}
You can play around with this code here on Scastie, alongside a couple of tests to verify it works as expected, which are the following:
def test[A](
input: List[A],
expected: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): Unit =
assert(
filterWhile(input)(filterP, whileP) == expected,
s"input: $input, expected: $expected, got: ${filterWhile(input)(filterP, whileP)}"
)
test(
input = List(0, 0, 0, 0, 0, 3, '.', 5, 0, 2, 5),
expected = List(3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)
test(
input = List(0, 0, 0, 1, 0, 3, '.', 5, 0, 2, 5),
expected = List(1, 3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)
test(
input = List(1, 2, 3, 4),
expected = List(1, 2, 3, 4)
)(filterP = _ < 5, whileP = _ < 5)
In your case in particular all you have to do is invoke the function as follows:
filterWhile(tempList)(_ != 0, _ != 3)
Where the first predicate says how to filter and the second defines the "while" clause. I chose to align the predicate ordering to the name of the function (it first says "filter" and then "while") but feel free to adjust according to your preference. In any case, using named parameters is probably a good thing here.
Combining existing functions on lists, I came up with:
def filterUntil[A](list: List[A], filter: A => Boolean, cond: A => Boolean): List[A] = {
list.takeWhile(cond).filter(filter) ++ list.dropWhile(cond)
}
This produces much the same results as #stefanobaghino's answer.
This might be done with a foldLeft but in this case I would got for a recursive routine:
def remove(list: List[Any]): List[Any] = {
def loop(rem: List[Any], res: List[Any]): List[Any] =
rem match {
case Nil =>
res
case 0 :: tail =>
loop(tail, res)
case 3 :: _ =>
res ++ rem
case x :: tail =>
loop(tail, res :+ x)
}
loop(list, Nil)
}
remove(List(0,0,0,0,0,3,".",5,0,2,5))
// List(3, ., 5, 0, 2, 5)
Note that this won't be efficient for long lists because adding to the tail of a List gets very slow with longs lists.
Also, as noted in the comments, you should avoid Any if possible and use a more specific type.
[ Simplifications thanks to #MikhailIonkin ]
Have there any way to split a list in dart based on a condition like following:
[1, 2, 3, 4, 5, 6, 7, 8] (A sample list)
After splitting it based on i % 2 == 0 condition,
it would generate the following two lists:
1) [1, 3, 5, 7]
2) [2, 4, 6, 8]
I know I can simply write a loop to go through all the elements and check the condition to create the two sublists. But have there any shorter functional way in dart?
Thanks in advance!
If you want to do this a lot it could be a good idea to create an extension method in your project which does what you want. I have come up with the following design which should work in a generic and efficient way:
void main() {
final s_list = [1, 2, 3, 4, 5, 6, 7, 8];
final match = s_list.splitMatch((element) => element % 2 == 0);
print(match.matched); // [2, 4, 6, 8]
print(match.unmatched); // [1, 3, 5, 7]
}
extension SplitMatch<T> on List<T> {
ListMatch<T> splitMatch(bool Function(T element) matchFunction) {
final listMatch = ListMatch<T>();
for (final element in this) {
if (matchFunction(element)) {
listMatch.matched.add(element);
} else {
listMatch.unmatched.add(element);
}
}
return listMatch;
}
}
class ListMatch<T> {
List<T> matched = <T>[];
List<T> unmatched = <T>[];
}
A quick solution:
var s_list = [1, 2, 3, 4, 5, 6, 7, 8];
s_list.where( (el) => el % 2 == 0 ).toList();
s_list.where( (el) => el % 2 != 0 ).toList();
I would like to know how can I create a List of List in the result of a reduce operation.
I've for example this lines
1,2,3,4
0,7,8,9
1,5,6,7
0,6,5,7
And I would like to get something like this
1, [[2,3,4],[5,6,7]]
0, [[7,8,9],[6,5,7]]
Thsi is my code
val parsedData = data.map { line =>
val parts = line.split(",")
val label = Integer.parseInt(parts(0))
(label, List(Integer.parseInt(parts(1)), Integer.parseInt(parts(2)), Integer.parseInt(parts(3)))
}
With this I get
1, [2,3,4]
0, [7,8,9]
1, [5,6,7]
0, [6,5,7]
But if I use a reduceByKey operation with a List.concat(_,_) I get one single List with all items concated.
parsedData.reduceByKey(List.concat(_,_))
I want a List of List, reduced by the Key.
Is there some other operation that i don't know?
Thanks a lot for your help!
Here is a working example:
val data = "1,2,3,4\n0,7,8,9\n1,5,6,7\n0,6,5,7".split("\n")
val parsedData = data.map{ line =>
val parts = line.split(",")
val label = Integer.parseInt(parts(0))
(label, List(Integer.parseInt(parts(1)), Integer.parseInt(parts(2)), Integer.parseInt(parts(3))))
}.toList
//parsedData: List[(Int, List[Int])] = List((1,List(2, 3, 4)), (0,List(7, 8, 9)), (1,List(5, 6, 7)), (0,List(6, 5, 7)))
parsedData.groupBy(_._1).mapValues(_.map(_._2))
// Map(1 -> List(List(2, 3, 4), List(5, 6, 7)), 0 -> List(List(7, 8, 9), List(6, 5, 7)))
I am not sure this is concat you are looking for.
Can you try with that:
parsedData.reduceByKey(_ :: _ :: Nil)
Which should literally create a new list with your elements inside
I have a List
val family=List("1","2","11","12","21","22","31","33","41","44","51","55")
i want to take its first n elements but the problem is that parents size is not fixed.
val familliar=List("1","2","11") //n=3
You can use take
scala> val list = List(1,2,3,4,5,6,7,8,9)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> list.take(3)
res0: List[Int] = List(1, 2, 3)
List(1,2,3).take(100) //List(1,2,3)
The signature of take will compare the argument with index, so the incremental index will never more than argument
The signature of take
override def take(n: Int): List[A] = {
val b = new ListBuffer[A]
var i = 0
var these = this
while (!these.isEmpty && i < n) {
i += 1
b += these.head
these = these.tail
}
if (these.isEmpty) this
else b.toList
}
Use take:
val familliar = family.take(3)