Scala how to remove item while matching other list itme - list

I have a 2 list of following class
case class User(var userId: Int =0,
var userName: String ="",
var email: String="",
var password: String ="") {
def this() = this(0, "", "", "")
}
globalList of User class.
localList of User class.
I would like to remove/filter all items from globalList that are same userId in localList.
I tried couple of api with no success such as filterNot, filter, drop, dropWhile. Please advice me how it can be done.

The diff operator "Computes the multiset difference between this list and another sequence".
scala> val global = List(0,1,2,3,4,5)
global: List[Int] = List(0, 1, 2, 3, 4, 5)
scala> val local = List(1,2,3)
local: List[Int] = List(1, 2, 3)
scala> global.diff(local)
res9: List[Int] = List(0, 4, 5)

You can try the following:
val userIdSet = localList.map(_.userId).toSet
val filteredList = globalList.filterNot(u => userIdSet.contains(u.userId))

Related

How to insert randomly an element into a List

Given a List[Int] l, how can I insert randomly a new element elem into the List[Int] l?
def randomInsert(l: List[Int], elem: Int): List[Int] = ???
This can be done by first, picking a random index into the list and then inserting the new element at that index. Also this can be done in a generic way:
import scala.util.Random
def randomInsert[A](l: List[A], elem: A): List[A] = {
val random = new Random
val randomIndex = random.nextInt(l.length + 1)
l.patch(randomIndex, List(elem), 0)
}
Usage:
scala>randomInsert(List(1,2,3,4,5),100)
res2: List[Int] = List(1, 2, 3, 4, 5, 100)
scala>randomInsert(List(1,2,3,4,5),100)
res3: List[Int] = List(100, 1, 2, 3, 4, 5)
scala>randomInsert(List(1,2,3,4,5),100)
res4: List[Int] = List(1, 2, 100, 3, 4, 5)
We can use this method to add recursively several elements:
import scala.util.Random
import scala.annotation.tailrec
def randomInsert[A](l: List[A], elem: A, elems: A*): List[A] = {
val random = new Random
#tailrec
def loop(elemToInsert: List[A], acc: List[A]): List[A] =
elemToInsert match {
case Nil => acc
case head :: tail =>
val randomIndex = random.nextInt(acc.length + 1)
loop(tail, acc.patch(randomIndex, List(head), 0))
}
loop(elem :: elems.toList, l)
}
Usage:
scala>randomInsert(List(1,2,3,4,5),100,101,102)
res10: List[Int] = List(1, 2, 101, 3, 4, 5, 100, 102)
scala>randomInsert(List(1,2,3,4,5),100,101,102)
res11: List[Int] = List(1, 2, 102, 100, 101, 3, 4, 5)
scala>randomInsert(List(1,2,3,4,5),100,101,102)
res12: List[Int] = List(1, 2, 3, 4, 100, 5, 102, 101)
Edit:
As per comment, an more efficient way to do this is to join both list and to shuffle the combined one - note than by doing so you may lose the original order of the list:
import scala.util.Random
def randomInsert[A](l: List[A], elem: A, elems: A*): List[A] = {
Random.shuffle((elem :: elems.toList) reverse_::: l)
}

Scala Escape Character Regex

How can I write an expression to filter inputs so that it would be in the format of
(AAA) where A is a number from 0-9.
EX: (123), (592), (999)
Usually you want to do more than filter.
scala> val r = raw"\(\d{3}\)".r
r: scala.util.matching.Regex = \(\d{3}\)
scala> List("(123)", "xyz", "(456)").filter { case r() => true case _ => false }
res0: List[String] = List((123), (456))
scala> import PartialFunction.{cond => when}
import PartialFunction.{cond=>when}
scala> List("(123)", "xyz", "(456)").filter(when(_) { case r() => true })
res1: List[String] = List((123), (456))
Keeping all matches from each input:
scala> List("a(123)b", "xyz", "c(456)d").flatMap(s =>
| r.findAllMatchIn(s).map(_.matched).toList)
res2: List[String] = List((123), (456))
scala> List("a(123)b", "xyz", "c(456)d(789)e").flatMap(s =>
| r.findAllMatchIn(s).map(_.matched).toList)
res3: List[String] = List((123), (456), (789))
Keeping just the first:
scala> val r = raw"(\(\d{3}\))".r.unanchored
r: scala.util.matching.UnanchoredRegex = (\(\d{3}\))
scala> List("a(123)b", "xyz", "c(456)d(789)e").flatMap(r.unapplySeq(_: String)).flatten
res4: List[String] = List((123), (456))
scala> List("a(123)b", "xyz", "c(456)d(789)e").collect { case r(x) => x }
res5: List[String] = List((123), (456))
Keeping entire lines that match:
scala> List("a(123)b", "xyz", "c(456)d(789)e").collect { case s # r(_*) => s }
res6: List[String] = List(a(123)b, c(456)d(789)e)
Java API:
scala> import java.util.regex._
import java.util.regex._
scala> val p = Pattern.compile(raw"(\(\d{3}\))")
p: java.util.regex.Pattern = (\(\d{3}\))
scala> val q = p.asPredicate
q: java.util.function.Predicate[String] = java.util.regex.Pattern$$Lambda$1107/824691524#3234474
scala> List("(123)", "xyz", "(456)").filter(q.test)
res0: List[String] = List((123), (456))
Typically you create regexes by using the .r method available on strings, such as "[0-9]".r. However, as you have noticed, that means you can't interpolate escape characters, as the parser thinks you want to insert escape characters into the string, not the regex.
For this, you can use Scala's triple-quoted strings, which create strings of the exact character sequence, including backslashes and newlines.
To create a regex like you describe, you could write """\(\d\d\d\)""".r. Here's an example of it in use:
val regex = """\(\d\d\d\)""".r.pattern
Seq("(123)", "(---)", "456").filter(str => regex.matcher(str).matches)

check for the specific element in the list -- scala

I want to find if the specific string is present in the list for example
val fruit: List[String] = List("apples", "oranges", "pears")
I want to check if oranges is present in the given list
It would be great if someone can help me on this. TIA
there are several ways to do that:
scala> val fruits: List[String] = List("apples", "oranges", "pears")
fruits: List[String] = List(apples, oranges, pears)
using .contains
scala> val hasApples = fruit.contains("apples")
hasApples: Boolean = true
scala> val hasBananas = fruit.contains("bananas")
bananas: Boolean = false
or using .find
scala> fruits.find(_ == "apples")
res1: Option[String] = Some(apples)
scala> fruits.find(_ == "bananas")
res2: Option[String] = None
check the documentation for other useful methods on: http://www.scala-lang.org/api/current/#scala.collection.immutable.List

How to count elements from list if specific key present in list using scala?

I have following list structure -
"disks" : [
{
"name" : "A",
"memberNo" :1
},
{
"name" : "B",
"memberNo" :2
},
{
"name" : "C",
"memberNo" :3
},
{
"name" : "D",
}
]
I have many elements in list and want to check for 'memberNo', if it exists
I want count of from list elements.
e.g. here count will be 3
How do I check if key exists and get count of elements from list using scala??
First create class to represent your input data
case class Disk (name : String, memberNo : String)
Next load data from repository (or other datasource)
val disks: List[Disk] = ...
And finally count
disks.count(d => Option(d.memberNo).isDefined)
In a similar fashion as in #SergeyLagutin answer, consider this case class
case class Disk (name: String, memberNo: Option[Int] = None)
where missing memberNo are defaulted with None; and this list,
val disks = List( Disk("A", Some(1)),
Disk("B", Some(2)),
Disk("C", Some(3)),
Disk("D"))
Then with flatMap we can filter out those disks with some memberNo, as follows,
disks.flatMap(_.memberNo)
res: List[Int] = List(1, 2, 3)
Namely, for the counting,
disks.flatMap(_.memberNo).size
res: Int = 3
Likewise, with a for comprehension,
for (d <- disks ; m <- d.memberNo) yield m
res: List[Int] = List(1, 2, 3)

How can I delete duplicates in a Dart List? list.distinct()?

How do I delete duplicates from a list without fooling around with a set? Is there something like list.distinct()? or list.unique()?
void main() {
print("Hello, World!");
List<String> list = ['abc',"abc",'def'];
list.forEach((f) => print("this is list $f"));
Set<String> set = new Set<String>.from(list);
print("this is #0 ${list[0]}");
set.forEach((f) => print("set: $f"));
List<String> l2= new List<String>.from(set);
l2.forEach((f) => print("This is new $f"));
}
Hello, World!
this is list abc
this is list abc
this is list def
this is #0 abc
set: abc
set: def
This is new abc
This is new def
Set seems to be way faster!! But it loses the order of the items :/
Use toSet and then toList
var ids = [1, 4, 4, 4, 5, 6, 6];
var distinctIds = ids.toSet().toList();
Result: [1, 4, 5, 6]
Or with spread operators:
var distinctIds = [...{...ids}];
I didn't find any of the provided answers very helpful.
Here is what I generally do:
final ids = Set();
myList.retainWhere((x) => ids.add(x.id));
Of course you can use any attribute which uniquely identifies your objects. It doesn't have to be an id field.
Benefits over other approaches:
Preserves the original order of the list
Works for rich objects not just primitives/hashable types
Doesn't have to copy the entire list to a set and back to a list
Update 09/12/21
You can also declare an extension method once for lists:
extension Unique<E, Id> on List<E> {
List<E> unique([Id Function(E element)? id, bool inplace = true]) {
final ids = Set();
var list = inplace ? this : List<E>.from(this);
list.retainWhere((x) => ids.add(id != null ? id(x) : x as Id));
return list;
}
}
This extension method does the same as my original answer. Usage:
// Use a lambda to map an object to its unique identifier.
myRichObjectList.unique((x) => x.id);
// Don't use a lambda for primitive/hashable types.
hashableValueList.unique();
Set works okay, but it doesn't preserve the order. Here's another way using LinkedHashSet:
import "dart:collection";
void main() {
List<String> arr = ["a", "a", "b", "c", "b", "d"];
List<String> result = LinkedHashSet<String>.from(arr).toList();
print(result); // => ["a", "b", "c", "d"]
}
https://api.dart.dev/stable/2.4.0/dart-collection/LinkedHashSet/LinkedHashSet.from.html
Try the following:
List<String> duplicates = ["a", "c", "a"];
duplicates = duplicates.toSet().toList();
Check this code on Dartpad.
If you want to keep ordering or are dealing with more complex objects than primitive types, store seen ids to the Set and filter away those ones that are already in the set.
final list = ['a', 'a', 'b'];
final seen = Set<String>();
final unique = list.where((str) => seen.add(str)).toList();
print(unique); // => ['a', 'b']
//This easy way works fine
List<String> myArray = [];
myArray = ['x', 'w', 'x', 'y', 'o', 'x', 'y', 'y', 'r', 'a'];
myArray = myArray.toSet().toList();
print(myArray);
// result => myArray =['x','w','y','o','r', 'a']
I am adding this to atreeon's answer. For anyone that want use this with Object:
class MyObject{
int id;
MyObject(this.id);
#override
bool operator ==(Object other) {
return other != null && other is MyObject && hashCode == other.hashCode;
}
#override
int get hashCode => id;
}
main(){
List<MyObject> list = [MyObject(1),MyObject(2),MyObject(1)];
// The new list will be [MyObject(1),MyObject(2)]
List<MyObject> newList = list.toSet().toList();
}
Remove duplicates from a list of objects:
class Stock {
String? documentID; //key
Make? make;
Model? model;
String? year;
Stock({
this.documentID,
this.make,
this.model,
this.year,
});
}
List of stock, from where we want to remove duplicate stocks
List<Stock> stockList = [stock1, stock2, stock3];
Remove duplicates
final ids = stockList.map((e) => e.documentID).toSet();
stockList.retainWhere((x) => ids.remove(x.documentID));
Using Dart 2.3+, you can use the spread operators to do this:
final ids = [1, 4, 4, 4, 5, 6, 6];
final distinctIds = [...{...ids}];
Whether this is more or less readable than ids.toSet().toList() I'll let the reader decide :)
For distinct list of objects you can use Equatable package.
Example:
// ignore: must_be_immutable
class User extends Equatable {
int id;
String name;
User({this.id, this.name});
#override
List<Object> get props => [id];
}
List<User> items = [
User(
id: 1,
name: "Omid",
),
User(
id: 2,
name: "Raha",
),
User(
id: 1,
name: "Omid",
),
User(
id: 2,
name: "Raha",
),
];
print(items.toSet().toList());
Output:
[User(1), User(2)]
Here it is, a working solution:
var sampleList = ['1', '2', '3', '3', '4', '4'];
//print('original: $sampleList');
sampleList = Set.of(sampleList).toList();
//print('processed: $sampleList');
Output:
original: [1, 2, 3, 3, 4, 4]
processed: [1, 2, 3, 4]
Using the fast_immutable_collections package:
[1, 2, 3, 2].distinct();
Or
[1, 2, 3, 2].removeDuplicates().toList();
Note: While distinct() returns a new list, removeDuplicates() does it lazily by returning an Iterable. This means it is much more efficient when you are doing some extra processing. For example, suppose you have a list with a million items, and you want to remove duplicates and get the first five:
// This will process five items:
List<String> newList = list.removeDuplicates().take(5).toList();
// This will process a million items:
List<String> newList = list.distinct().sublist(0, 5);
// This will also process a million items:
List<String> newList = [...{...list}].sublist(0, 5);
Both methods also accept a by parameter. For example:
// Returns ["a", "yk", "xyz"]
["a", "yk", "xyz", "b", "xm"].removeDuplicates(by: (item) => item.length);
If you don't want to include a package into your project but needs the lazy code, here it is a simplified removeDuplicates():
Iterable<T> removeDuplicates<T>(Iterable<T> iterable) sync* {
Set<T> items = {};
for (T item in iterable) {
if (!items.contains(item)) yield item;
items.add(item);
}
}
Note: I am one of the authors of the fast_immutable_collections package.
void uniqifyList(List<Dynamic> list) {
for (int i = 0; i < list.length; i++) {
Dynamic o = list[i];
int index;
// Remove duplicates
do {
index = list.indexOf(o, i+1);
if (index != -1) {
list.removeRange(index, 1);
}
} while (index != -1);
}
}
void main() {
List<String> list = ['abc', "abc", 'def'];
print('$list');
uniqifyList(list);
print('$list');
}
Gives output:
[abc, abc, def]
[abc, def]
As for me, one of the best practices is sort the array, and then deduplicate it. The idea is stolen from low-level languages. So, first make the sort by your own, and then deduplicate equal values that are going after each other.
// Easy example
void dedup<T>(List<T> list, {removeLast: true}) {
int shift = removeLast ? 1 : 0;
T compareItem;
for (int i = list.length - 1; i >= 0; i--) {
if (compareItem == (compareItem = list[i])) {
list.removeAt(i + shift);
}
}
}
// Harder example
void dedupBy<T, I>(List<T> list, I Function(T) compare, {removeLast: true}) {
int shift = removeLast ? 1 : 0;
I compareItem;
for (int i = list.length - 1; i >= 0; i--) {
if (compareItem == (compareItem = compare(list[i]))) {
list.removeAt(i + shift);
}
}
}
void main() {
List<List<int>> list = [[1], [1], [2, 1], [2, 2]];
print('$list');
dedupBy(list, (innerList) => innerList[0]);
print('$list');
print('\n removeLast: false');
List<List<int>> list2 = [[1], [1], [2, 1], [2, 2]];
print('$list2');
dedupBy(list2, (innerList) => innerList[0], removeLast: false);
print('$list2');
}
Output:
[[1], [1], [2, 1], [2, 2]]
[[1], [2, 1]]
removeLast: false
[[1], [1], [2, 1], [2, 2]]
[[1], [2, 2]]
This is another way...
final reducedList = [];
list.reduce((value, element) {
if (value != element)
reducedList.add(value);
return element;
});
reducedList.add(list.last);
print(reducedList);
It works for me.
var list = [
{"id": 1, "name": "Joshua"},
{"id": 2, "name": "Joshua"},
{"id": 3, "name": "Shinta"},
{"id": 4, "name": "Shinta"},
{"id": 5, "name": "Zaidan"}
];
list.removeWhere((element) => element.name == element.name.codeUnitAt(1));
list.sort((a, b) => a.name.compareTo(b.name));
Output:
[{"id": 1, "name": "Joshua"},
{"id": 3, "name": "Shinta"},
{"id": 5, "name": "Zaidan"}]
List<Model> bigList = [];
List<ModelNew> newList = [];
for (var element in bigList) {
var list = newList.where((i) => i.type == element.type).toList();
if(list.isEmpty){
newList.add(element);
}
}
Create method to remove duplicates from Array and return Array of unique elements.
class Utilities {
static List<String> uniqueArray(List<String> arr) {
List<String> newArr = [];
for (var obj in arr) {
if (newArr.contains(obj)) {
continue;
}
newArr.add(obj);
}
return newArr;
}
}
You can use the following way:
void main(List <String> args){
List<int> nums = [1, 2, 2, 2, 3, 4, 5, 5];
List<int> nums2 = nums.toSet().toList();
}
NOTE: This will not work if the items in the list are objects of class and have the same attributes. So, to solve this, you can use the following way:
void main() {
List<Medicine> objets = [Medicine("Paracetamol"),Medicine("Paracetamol"), Medicine("Benylin")];
List <String> atributs = [];
objets.forEach((element){
atributs.add(element.name);
});
List<String> noDuplicates = atributs.toSet().toList();
print(noDuplicates);
}
class Medicine{
final String name;
Medicine(this.name);
}
This is my solution
List<T> removeDuplicates<T>(List<T> list, IsEqual isEqual) {
List<T> output = [];
for(var i = 0; i < list.length; i++) {
bool found = false;
for(var j = 0; j < output.length; j++) {
if (isEqual(list[i], output[j])) {
found = true;
}
}
if (found) {
output.add(list[i]);
}
}
return output;
}
Use it like this:
var theList = removeDuplicates(myOriginalList, (item1, item2) => item1.documentID == item2.documentID);
or...
var theList = removeDuplicates(myOriginalList, (item1, item2) => item1.equals(item2));
or...
I have a library called Reactive-Dart that contains many composable operators for terminating and non-terminating sequences. For your scenario it would look something like this:
final newList = [];
Observable
.fromList(['abc', 'abc', 'def'])
.distinct()
.observe((next) => newList.add(next), () => print(newList));
Yielding:
[abc, def]
I should add that there are other libraries out there with similar features. Check around on GitHub and I'm sure you'll find something suitable.