How to compare sublists in List[List[Double]] - list

I have a List[List[Double]]
Ignoring the last element of each list with in outer list, I want to compare inner lists i.e. we have a
List(
List(0.1,0.5,0.3,0),
List(2.3,0.1,0.4,1),
List(0.1,0.5,0.3,1)
)
I want distinct list ignoring last element i.e.
List(
List(0.1,0.5,0.3,0),
List(2.3,0.1,0.4,1)
)
Here the 1st and last lists are similar ignoring the last elements.
kindly provide me some clue. As I am very new to scala.

Study the Standard Library. It's amazing the things you can find there.
List(List(0.1,0.5,0.3,0),List(2.3,0.1,0.4,1),List(0.1,0.5,0.3,1)).distinctBy(_.init)
//res0: List[List[Double]] = List(List(0.1, 0.5, 0.3, 0.0), List(2.3, 0.1, 0.4, 1.0))

If you're on Scala 2.13+ please see #jwvh's solution, otherwise ...
You could traverse the list via foldLeft to assemble a new list of inner lists by checking against a Set of lists with distinct init:
val list = List(List(0.1, 0.5, 0.3, 0.0), List(2.3, 0.1, 0.4, 1.0), List(0.1, 0.5, 0.3, 1.0))
list.foldLeft((List[List[Double]](), Set[List[Double]]())){ case ((ls, s), l) =>
val lInit = l.init
if (s.contains(lInit)) (ls, s) else (l :: ls, s + lInit)
}._1.reverse
// res1: List[List[Double]] = List(List(0.1, 0.5, 0.3, 0.0), List(2.3, 0.1, 0.4, 1.0))
In case order of the resulting inner lists is unimportant, an alternative is to group the list by the inner list's init, followed by extracting the first inner list from the grouped Map values:
list.groupBy(_.init).map(_._2.head)
// res2: List[List[Double]] = List(List(2.3, 0.1, 0.4, 1.0), List(0.1, 0.5, 0.3, 0.0))

Related

Scala: Sorting a list while keeping the position of placeholders

The problem I'm facing is sorting a List of Double values in Scala also containing some kind of placeholder values (Double.NaN in the example below. However, these can be set as required for the sorting to work.), which should keep their position after sorting.
Input:
val placeholder = Double.NaN
List(placeholder, 5.0, 2.0, placeholder, 4.0, 3.0, placeholder)
Output:
List(placeholder, 2.0, 3.0, placeholder, 4.0, 5.0, placeholder)
How can I sort Double values in a list without altering the position of placeholder values?
I'm searching for a solution to work with Scala 2, specifically 2.12
Thanks for your help!
One way is to sort the list and insert back the placeholders at right position.
This is not optimal, optimisation left to the reader as an exercise, but here's the idea:
val placeholder = Double.NaN
val list = List(placeholder, 5.0, 2.0, placeholder, 4.0, 3.0, placeholder)
val sorted = list.filterNot(_.isNaN).sorted
def insertSorted(in: List[Double], sorted: List[Double]): List[Double] = {
in match {
case Nil => Nil
case head :: tail =>
if (head.isNaN)
placeholder :: insertSorted(tail, sorted)
else
sorted.head :: insertSorted(tail, sorted.tail)
}
}
insertSorted(list, sorted)
// List(NaN, 2.0, 3.0, NaN, 4.0, 5.0, NaN)
This only works with NaN as placeholder. If using another value (like -1), regular comparison should be used.
Also, as raised in the comments, comparison on doubles can lead to surprises, use with caution.
This solution could also be written as a fold:
def sort(list: List[Double]): List[Double] = {
val (sorted, _) = list
.foldLeft((List.empty[Double], list.sorted)) { case ((result, sortedInput), n) =>
if (n.isNaN) (result :+ placeholder, sortedInput)
else (result :+ sortedInput.head, sortedInput.tail)
}
sorted
}
Again not optimal, but possibly the most straightforward if performance is not a high priority.
foldRight is stack safety
def sort(in: List[Double]): List[Double] = {
val sortedIn = in.filterNot(_.isNaN).sorted.reverse
val (result, _) = in.foldRight((List.empty[Double], sortedIn)) {
case (n, (result, list)) =>
if (n.isNaN) (placeholder :: result, list)
else (list.head :: result, list.tail)
}
result
}

Opperations inside a list with different elements

The teacher assistant assigned me this problem but I could not understand if this op is possible:
Create a list with int, str and float: my_list = [2, 3, 0.5, "cams"]
print only the odd numbers in this list
I am not sure if I can operate conditions in a list with different elements. Please help!
Python:
my_list = [2, 3, 0.5, "cams"]
for i in my_list:
if type(i) is not str and i%2 == 1:
print(i)
JS:
my_list = [2, 3, 0.5, "cams"]
for(let i=0;i<my_list.length;i++){
if(typeof(my_list[i]) != "string" && i%2 == 1){
console.log(my_list[i])
}
}
Output:
3

Casting all elements of a list of lists to float in python

I'm trying to cast all elements on a list of lists to float but when I do it like on the first loop below and then print their type, their types keep being the original ones.
for x in f:
for a in x:
a = float(a)
for x in f:
for a in x:
print(type(a),a)
Out of the print I get
<class 'numpy.str_'> 0.0
<class 'float'> 0.0
<class 'float'> 1.0
<class 'float'> nan
<class 'numpy.float64'> 0.3
Shouldn't the first loop change the elements' types?
for x in f:
for a in x:
a = float(a)
This does not update the element in the list like you'd expect. You're just assigning a to a new variable.
There are many ways of doing this but one way would be to recreate your list. Here's a simple example
a = [ "1", "2", "3" ]
a = [ float(x) for x in a ]
print(a) # Yield [1.0, 2.0, 3.0]
Another way is directly update the item in the list
for index, a in enumerate(x):
x[index] = float(a)

Addition of tow list with different list lengthes

I am trying to remove the strings from a list and then find the sum of the new list with a list which has smaller length.
I have written a code which does not work at 3-4 places. I have some question,
why does the if statement does not work propely?
How can I write the addition function for this kind of list with differnt lenght?
This is my code:
def remove_text_from_list(the_list):
z = []
for x in the_list:
if isinstance(x, float):
z.append(x)
return z
def add(a,b):
return a+b
x = []
list1=['s', 1.0, 2.0, 'a', 3.0, 4.0,'b', 5.0, 6.0,'c', 7.0, 8.0]
list2=[10.0, 20.0]
newlist=remove_text_from_list(list1)
for i in newlist:
for j in list2:
f = add(i,j)
final_list.append(f)
print(x)
The desired result should be like following:
final_list=[11,22,13,24,15,26,17,28]
Use a generator expression to create a generator that yields floats from list1. Use itertools.cycle to iterate over list2 repeatedly as needed. Use zip to pair the floats from list1 with the cycled items from list2 and add them together in a list comprehension.
>>> from itertools import cycle
>>> just_floats = (i for i in list1 if isinstance(i, float))
>>> [a+b for a, b in zip(just_floats, cycle(list2))]
[11.0, 22.0, 13.0, 24.0, 15.0, 26.0, 17.0, 28.0]
You return the list in the if-statement. If you do it at the end of the for-loop it should work:
def remove_text_from_list(the_list):
z = []
for x in the_list:
if isinstance(x, float):
z.append(x)
return z
But still x will not be your expected final_result but:
x = [11.0, 21.0, 12.0, 22.0, 13.0, 23.0, 14.0, 24.0, 15.0, 25.0, 16.0, 26.0, 17.0, 27.0, 18.0, 28.0]

How do I generate a List using tabulate who's entries are squared in Scala?

I'm new to Scala and I'm trying to generate a List using the tabulate() method.
I see that it's used this way and it works perfectly fine,
val myList = List.tabulate(10)(_ * 2)
but this doesn't
val myList = List.tabulate(10)(_ * _)
whereas, I got what I wanted by,
val myList = List.tabulate(10)(n => n * n)
Can I know why didn't the second example work?
An anonymous function represented with underscores is expected to have the same number of arguments as underscores. The particular overload of List.tabulate you are using (for one-dimension) expects a function with only argument, but you provide a function with two.
In other words _ * _ expands to (a, b) => a * b and it is not possible to represent a => a * a with just underscores.
Alternatively, you could use math.pow(_, 2) as your squaring function, but it returns Double instead of Int.
scala> List.tabulate(10)(math.pow(_, 2))
res0: List[Double] = List(0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0, 81.0)