List.Sort by Substring in PowerQuery (M) - list

I have a list of strings I'm trying to sort:
List
F20
S20
S21
F21
I would like my sort to result as below: by the 2 digit number first, then the 1 character letter. However, I can't create a static order for the sort because the strings will update/change over time:
List
S20
F20
S21
F21
Is there a List.Sort syntax/property in PowerQuery M I can use to sort by substrings within a list? If not, is there any elegant way of accomplishing this without a static list order?

You need to define a custom comparator and pass it as a second arg to List.Sort. Here is code, assuming that each item has only 1 letter
let
list = {"F20", "S20", "S21", "F21"},
transform = (value) => Text.Range(value, 1) & Text.Range(value, 0, 1)
in
List.Sort(list, (a, b) => Value.Compare(transform(a), transform(b)))
results in
F20
S20
F21
S21

you can achieve this using keys
inputList = ['F20', 'S20', 'F21', 'S21']
sortedList = sorted(inputList, key=lambda item: item[0:1], reverse=True)
sortedList = sorted(sortedList, key=lambda item: item[1:])
print(sortedList)

Related

Need to combine two list in scala with some condition for replacement

I want to do this :
val list1 = List(Student("ivan","history",45))
val list2 = List(Student("ivan","history",40),Student("alexander","physics",81),Student("vlad","math",70))
I want to combine list1 and list2 so that list1's element remove list's 2 element based on student name and subject.
Required Output :
List(Student("ivan","history",45),Student("alexander","physics",81),Student("vlad","math",70))
I would go for a groupBy here. You concatenate the two lists, then you groupBy and take the head element for each key. This will scrumble the order among students though, but is efficient.
(list1 ++ list2)
.groupBy(s => (s.name, s.subject))
.map { case (key, values) =>
values.head
}
You can define a function to check if two Student values match:
def isSame(s: Student, t: Student): Boolean = (s.name == t.name && s.sub == t.sub)
Using this you can iterate over list2 and check if there is a match in list1. If there is, you use the value from list1 else keep the value from list2.
list2.map(s2 => (list1.map(s1 => if (isSame(s1, s2)) s1 else s2))).flatten
Note that this might not be the most optimal solution if the two lists are huge.

Scala iterate over two consecutive elements of a list

How would we iterate over two consecutive elements of a list and apply the difference function
For instance I have this :
val list = List(List("Eat", "Drink", "Sleep", "work"), List("Eat", "Sleep", "Dance"))
I want to iterate over these two consecutive elements and calculate the difference
I've tried this but I do not know how to iterate over each two consecutive elements
list.map((a,b) => a.diff(b))
the output should be List("Drink", "work")
If I understand correctly you probably want to iterate over a sliding window.
list.sliding(2).map{
case List(a, b) => a.diff(b)
case List(a) => a
}.toList
Alternatively you might also want grouped(2) which partitions the list into groups instead.
def main(args: Array[String]): Unit = {
val list = List(List("Eat", "Drink", "Sleep", "work"), List("Eat", "Sleep", "Dance"));
val diff = list.head.diff(list(1))
println(diff)
}
In your case, match can work perfectly fine:
val list = List(List("Eat", "Drink", "Sleep", "work"), List("Eat", "Sleep", "Dance"))
list match { case a :: b :: Nil => a diff b}
If the list does not always have 2 items, you should also have a catch-all case in match

How to check a list contains substring from other list using scala?

I have following lists-
A = List(("192.168.20.1", "WinInfra", List("naa.6d867d9c7ac")),
("192.168.20.1", "TriSQLFreshInstall", List("naa.6d867d",
"naa.42704fdc4")),
("192.168.20.1", "redHat7", List("naa.4270cdf",
"naa.427045dc")))
B = List("4270cdf", "427045dc", "42704fdc4")
I want to check if last element of list A (it is a list of strings) contains any substring from list B and get output as unmatched elements only.
Edit: I want to check if any element of list B is exist in list A and collect only such list elements from list A which do not contains list B elements.
I want following output-
List(("192.168.20.1","WinInfra",List( "naa.6d867d9c7ac")))
How do I get above output using scala??
I think something like this:
A.filterNot(a => B.exists(b => a._3.exists(str => str.contains(b))))
or
A.filterNot(a => a._3.exists(str => B.exists(b => str.contains(b))))
or shorter, but less readable
A.filterNot(_._3 exists (B exists _.contains))
First, I wouldn't pass around tuples. It would be a lot easier if you would put this data structure into an object and work with that. However, it would be easier start by finding matches first. So you'll start out by applying a filter on List A:
A.filter { (ip, disc, sublist) => .... }
Where items in your sublist items are in List B:
sublist.exists(sublistItem => b.contains(sublistItem.replaceAll("naa.", "")))
This returns:
res1: List[(String, String, List[String])] = List((192.168.20.1,TriSQLFreshInstall,List(naa.6d867d, naa.42704fdc4)), (192.168.20.1,redHat7,List(naa.4270cdf, naa.427045dc)))
Which is the opposite of what you want. This is easy to correct by saying filterNot:
A.filterNot { (ip, disc, sublist) => sublist.exists(sublistItem => b.contains(sublistItem.replaceAll("naa.", ""))) }

Scala partition into more than two lists

I have a list in Scala that I'm trying to partition into multiple lists based on a predicate that involves multiple elements of the list. For example, if I have
a: List[String] = List("a", "ab", "b", "abc", "c")
I want to get b: List[List[String]] which is a List of List[String] such that the sum of the lengths of the inner List[String] == 3. i.e List(List("a", "b", "c"), List("abc"), List("ab", "a"), ...)
[Edit] Needs to take a reasonable time for lists of length 50 or less.
It is not possible to build an efficient algorithm that is cheaper than O(2^n * O(p)) for any arbitrary predicate, p. This is because every subset must be evaluated. You will never achieve something that works for n == 50.
Build all possible sublists and filter:
def filter[A](list: List[A])(predicate: (List[A] => Boolean)): List[List[A]] = {
(for {i <- 1 to list.length
subList <- list.combinations(i)
if predicate(subList)
} yield subList).toList
}
val a = List("a", "ab", "b", "abc", "c")
val result = filter(a)(_.foldLeft(0)(_ + _.length) == 3)
I think Sergey is on a good track here, but we can optimize his code a little bit. First of all, we can notice that if the sum of string lengths is N then for sure we don't need to check combinations composed of more than N strings, as the shortest string is at least one character long. And, additionally, we can get away without for synctatic sugar and use the sum method instead of a much more generic (and thus, probably, not so quick) foldLeft.
For clarity's sake, let's first define a small helper function which will compute the sum of strings lengths:
def sumOfStr(list: List[String]) = list.map(_.length).sum
And now the main method:
def split(list: List[String], sum: Int) =
(1 to sum).map(list.combinations(_).filter(sumOfStr(_) == sum)).flatten.toList
EDIT: With our powers combined, we give you a still very inefficient, but hey-that's-the-best-we-can-do-in-reasonable-time version:
def sumOfStr(lst: List[String]) = {
var sum = 0
lst.foreach{ sum += _.length }
sum
}
def split(lst: List[String], sum: Int) =
(1 to sum).par
.map(lst.combinations(_).filter(sumOfStr(_) == sum))
.flatten.toList

Scala conditional sum of elements in a filtered tuples list

I'm new to Scala and need a little help about how to combine
filters and sum on a list of tuples.
What I need is the sum of integers of a filtered tuples list which
essentially the answer to the question:
What is the sum of all set weights?
The result should be 20 for the sample list below
The list is pretty simple:
val ln = List( ("durationWeight" , true, 10),
("seasonWeight" , true, 10),
("regionWeight" , false, 5),
("otherWeight" , false, 5)
Filtering the list according to the Boolean flag is a simple:
val filtered = ln.filter { case(name, check, value) => check == true }
which returns me the wanted tuples. Getting the sum of all them seems to work
with a map followed by sum:
val b = filtered.map{case((name, check, value) ) => value}.sum
Which returns me the wanted sum of all set weights.
However, how do I do all that in one step combining filter, map and sum,
ideally in an elegant one liner?
Thanks for your help.
ln.collect{ case (_, true, value) => value }.sum
Another approach for the heck of it:
(0 /: ln)((sum,x) => if (x._2) sum + x._3 else sum)