Scala Code - Immutable Set Issues - algorithm

I'm learning Scala and I would like to convert some of my old algorithms code to Scala.
I have very simple Java code which prints superSet (a combination of all possible sets including empty set and the set itself).
public static Set<Set<Integer>> createSuperSet(Set<Integer> originalSet){
Set<Set<Integer>> superSet = new HashSet<Set<Integer>>();
if (originalSet.size() == 0){
Set<Integer> empty = new HashSet<Integer>();
superSet.add(empty);
return superSet;
}
List<Integer> list = new ArrayList<Integer>(originalSet);
Integer head = list.get(0);
Set<Integer> rest = new HashSet<Integer>(list.subList(1, list.size()));
for (Set<Integer> set : createSuperSet(rest)){
Set<Integer> newSet = new HashSet<Integer>();
newSet.add(head);
newSet.addAll(set);
superSet.add(newSet);
superSet.add(set);
}
return superSet;
}
Now I'm trying to achieve the same functionality in Scala:
def createSuperSet(originalSet: Set[Int]): Set[Set[Int]] ={
val superSet = Set[Set[Int]]()
originalSet.toList match {
case List() => {superSet + Set[Int]()}
case head::restAsList => {
val rest = restAsList.toSet[Int]
val result = createSuperSet(rest)
result.foreach(f=>{
val newSet:Set[Int] = f + head
superSet + f +newSet
})
superSet
}
}
}
but unfortunately this code returns empty Set. I'm suspecting that this issue happens due to Immutable collection usage. I was trying to run it in Debugger and I see that recursive call to function always returns empty set and my code is never getting into foreach function.
Please help. Any thoughts are welcomed.

In idiomatic scala the + (and -, ++, etc) operator as applied to immutable collections creates a new collection - otherwise they would not be immutable. Instead you have to combine the modification with another piece of syntactic sugar under which if you append = to an operator it assigns the result of the operator to the left-hand variable: superSet += f + newSet.

I solved the problem this way:
def createSuperSet(originalSet: Set[Int]): Set[Set[Int]] ={
var superSet = Set[Set[Int]]()
originalSet.toList match {
case List() => {superSet + Set[Int]()}
case head::restAsList => {
val rest = restAsList.toSet[Int]
val result = createSuperSet(rest)
result.map(f=>{
superSet = superSet + f+ (f+head)
})
superSet
}
}
}
running println(createSuperSet(Set[Int](1,2,3))
prints
Set(Set(), Set(3, 1), Set(2), Set(2, 1), Set(3, 2), Set(3), Set(3, 2, 1), Set(1))
but I'll be very glad to find out if there is any more elegant solution

Related

Flux returns unsorted data for StepVerifier

I expect to receive two elements after writing three to the database. The query returns a Flux, which returns the elements unsorted.
#Test
fun `SUCESSFULLY query pending purchases`() {
// arrange
val arrived = TestDataFactory.buchungssatzEntity(
sequentialId = 1,
arrived = true
)
val pending = TestDataFactory.buchungssatzEntity(
sequentialId = 2,
arrived = false
)
val next_pending = TestDataFactory.buchungssatzEntity(
sequentialId = 3,
arrived = false
)
// act
buchhaltungWriter.save(arrived)
buchhaltungWriter.save(pending)
buchhaltungWriter.save(next_pending)
val purchases = inventoryFinder.findAllPendingPurchases()
// assert
StepVerifier.create(purchases)
.expectNext(pending)
.expectNext(next_pending)
.verifyComplete()
}
This always throws
expected value: BuchungssatzEntity(... sequentialId=2 ...); actual value: BuchungssatzEntity(... sequentialId=3 ...)
I do not want to add sorting to the database query, it's a waste of time. How can I test Flux with 'all of these elements but in any order' or should I just go for a Mono in this case, return a list and do the rest myself? Then again, that's not why I'm using reactive.
PS: Goal of this test is to verify that my Spring query language statement filters correctly.
-------- UPDATE
I solved it by using
StepVerifier.create(inventoryFinder.findAllPendingPurchases())
.recordWith { listOf<PurchasesModel>() }
.thenConsumeWhile { i: Any? -> purchases.contains(i) }
.consumeRecordedWith{ }
.verifyComplete()
One way to do that is to use the thenConsumeWhile operator along with expectNextCount. If there is any element in the sequence that doesn't match, the StepVerifier will error.
In Java:
List<Item> pendingItems = List.of(pending, next_pending);
Flux<Item> items = inventoryFinder.findAllPendingPurchases();
StepVerifier.create(items)
.expectNextCount(2) //expecting 2 elements
.verifyComplete();
StepVerifier.create(items)
.thenConsumeWhile((i) -> pendingItems.contains(i)) // check if element was expected
.verifyComplete();

add data to an arrayList, when If condition is satisfied in nested for loop in Kotlin

Check the code below:
getCommonsArrayList(listA:ArrayList< User >, listB:ArrayList<User>):ArrayList<User>{
var listCommon = ArrayList<User>()
for (i in listA.indices) {
for (j in listB.indices) {
if (listA[i].id.equals(listB[j].id)) { //if id of the user matches
listCommon.put(listA[i]) //add to a new list
}
}
}
return listCommon // return the new list with common entries
}
The above method iterates list a & b and check whether the id's are matching, if they are then the User object is stored to a new list and at the end of the program, it returns the common list.
This thing works good. And I hope nested for followed by if condition is the way in which we can compare two lists.
The problem with this is if listA has repeated entries, then the listCommon will also have repeated entries as ArrayList supports duplicacy of entries.
So what I did to make commonList unique is I introduced a HashMap object as shown below:
getCommonsArrayList(listA:ArrayList< User >, listB:ArrayList<User>):ArrayList<User>{
var listCommon = ArrayList<User>()
var arrResponseMap = HashMap<String,User>()
for (i in listA.indices) {
for (j in listB.indices) {
if (listA[i].id.equals(listB[j].id)) { //if id of the user matches
arrResponseMap.put(listA[i].id,listA[i]) // add id to map so there would be no duplicacy
}
}
}
arrResponseMap.forEach {
listCommon.add(it.value) //iterate the map and add all values
}
return listCommon // return the new list with common entries
}
This will give the new arrayList of userObject with common Id's. But this has an increased complexity than the above code.
If the size of the listA and listB increases to 1000 then this execution will take heavy time.
Can someone guide me if there is some better way to solve this.
You can simply use distinctBy to get only unique values from list.
Official Doc:
Returns a sequence containing only elements from the given sequence
having distinct keys returned by the given selector function.
The elements in the resulting sequence are in the same order as they
were in the source sequence.
Here is an example:
val model1 = UserModel()
model1.userId = 1
val model2 = UserModel()
model1.userId = 2
val model3 = UserModel()
model1.userId = 1
val model4 = UserModel()
model1.userId = 2
val commonList = listOf(model1, model2, model3, model4)
// get unique list based on userID, use any field to base your distinction
val uniqueList = commonList
.distinctBy { it.userId }
.toList()
assert(uniqueList.count() == 2)
assert(commonList.count() == 4)
Add the both the list and use distinctBy like this
data class DevelopersDetail(val domain: String, val role: String)
val d1 = DevelopersDetail("a", "1")
val d2 = DevelopersDetail("b", "1")
val d3 = DevelopersDetail("c", "1")
val d4 = DevelopersDetail("c", "1")
val d5 = DevelopersDetail("d", "1")
var listA = listOf(d1, d2, d3, d4)
var listb = listOf(d1, d2, d3, d4)
var data = listA + listb
var list= data
.distinctBy { it.domain }
.toList()
println("list $list")
//output-list [DevelopersDetail(domain=a, role=1), DevelopersDetail(domain=b, role=1), DevelopersDetail(domain=c, role=1)]

IN operator in Couchbase Lite

I need to query something like
SELECT * FROM `sample` WHERE id IN ["123", "456"]
This is converted into QueryBuilder as below
QueryBuilder
.select(SelectResult.all())
.from(DataSource.database("sample"))
.where(Expression.property("id")
.in([
Expression.string("123"),
Expression.string("456")
])
)
This doesn't work, and return empty list of result, any idea?
I see from your comments that your code worked (it was false negative). Yet I'll share an approach which may be useful in case you need to use the like operator against multiple wildcarded (%) expressions. Sample is in Kotlin language:
val list = listOf("123", "456")
val items = list.map { Meta.id.like(Expression.string("$it-%")) }.toMutableList()
val whereExpression = items
.fold(items.removeAt(0)) { chain, next -> chain.or(next) }
val query = QueryBuilder.select(
SelectResult.expression(Meta.id),
SelectResult.all()
).from(DataSource.database(this.db)).where(whereExpression)
val results = query.execute()
val resultList = results.allResults()

What's a concise way of sorting and grouping a set in Kotlin?

From a set of Comparable objects I would like to get a sorted list of sets of objects, sorted by their natural order.
This is my solution:
val set: Set<Comparable<A>> = makeThings()
val sorted = set.sorted()
val sortedAndGrouped = mutableListOf(mutableSetOf(sorted.first()))
for(element in sorted.drop(1)) {
val randomElementOfLastGroup = sortedAndGrouped.last().first()
val doesNotBelongToLastGroup = randomElementOfLastGroup.compareTo(element) != 0
if(doesNotBelongToLastGroup)
sortedAndGrouped.add(mutableSetOf())
sortedAndGrouped.last().add(element)
}
I would like to know if there is a more concise alternative in Kotlin.
If not, is there one using Java 8 features or a library like Guava?
I would try something like this:
fun <A : Comparable<A>> alternativeSortAndGroup(set: Set<A>): List<Set<A>> =
set.sorted().groupBy { it }.values.map { it.toSet() }

Most efficient way to determine if there are any differences between specific properties of 2 lists of items?

In C# .NET 4.0, I am struggling to come up with the most efficient way to determine if the contents of 2 lists of items contain any differences.
I don't need to know what the differences are, just true/false whether the lists are different based on my criteria.
The 2 lists I am trying to compare contain FileInfo objects, and I want to compare only the FileInfo.Name and FileInfo.LastWriteTimeUtc properties of each item. All the FileInfo items are for files located in the same directory, so the FileInfo.Name values will be unique.
To summarize, I am looking for a single Boolean result for the following criteria:
Does ListA contain any items with FileInfo.Name not in ListB?
Does ListB contain any items with FileInfo.Name not in ListA?
For items with the same FileInfo.Name in both lists, are the FileInfo.LastWriteTimeUtc values different?
Thank you,
Kyle
I would use a custom IEqualityComparer<FileInfo> for this task:
public class FileNameAndLastWriteTimeUtcComparer : IEqualityComparer<FileInfo>
{
public bool Equals(FileInfo x, FileInfo y)
{
if(Object.ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.FullName.Equals(y.FullName) && x.LastWriteTimeUtc.Equals(y.LastWriteTimeUtc);
}
public int GetHashCode(FileInfo fi)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + fi.FullName.GetHashCode();
hash = hash * 23 + fi.LastWriteTimeUtc.GetHashCode();
return hash;
}
}
}
Now you can use a HashSet<FileInfo> with this comparer and HashSet<T>.SetEquals:
var comparer = new FileNameAndLastWriteTimeUtcComparer();
var uniqueFiles1 = new HashSet<FileInfo>(list1, comparer);
bool anyDifferences = !uniqueFiles1.SetEquals(list2);
Note that i've used FileInfo.FullName instead of Name since names aren't unqiue at all.
Sidenote: another advantage is that you can use this comparer for many LINQ methods like GroupBy, Except, Intersect or Distinct.
This is not the most efficient way (probably ranks a 4 out of 5 in the quick-and-dirty category):
var comparableListA = ListA.Select(a =>
new { Name = a.Name, LastWrite = a.LastWriteTimeUtc, Object = a});
var comparableListB = ListB.Select(b =>
new { Name = b.Name, LastWrite = b.LastWriteTimeUtc, Object = b});
var diffList = comparableListA.Except(comparableListB);
var youHaveDiff = diffList.Any();
Explanation:
Anonymous classes are compared by property values, which is what you're looking to do, which led to my thinking of doing a LINQ projection along those lines.
P.S.
You should double check the syntax, I just rattled this off without the compiler.

Resources