Comparable class with a List<String> field - java-8

I have a simple class which stores an integer and a list of Strings.
As I want to use this class in a TreeSet<>, the one must be Comparable.
But when trying to use the Java 8 Comparator class, I cannot compare my inner list.
I have the following error:
Bad return type in method reference: cannot convert java.util.List to U
I think there is a very simple way to do that but I could not find it out.
How to do that?
public class MyClass implements Comparable<MyClass> {
private final int someInt;
private final List<String> someStrings;
public MyClass (List<String> someStrings, int someInt) {
this.someInt = someInt;
this.someStrings = new ArrayList<>(someStrings);
}
#Override
public int compareTo(MyClass other) {
return
Comparator.comparing(MyClass::getSomeInt)
.thenComparing(MyClass::getSomeStrings) // Error here
.compare(this, other);
}
public int getSomeInt() {
return someInt;
}
public List<String> getSomeStrings() {
return someStrings;
}
}
Edit 1
I just want the String list to be compared in the simplest way (using implicitly String.compareTo()).
Note that I do now want to sort my List<String> but I want it to be Comparable so that MyClass is also comparable and finally, I can insert MyClass instances into a TreeSet<MyClass>.
A also saw in the JavaDoc the following:
java.util.Comparator<T> public Comparator<T>
thenComparing(#NotNull Comparator<? super T> other)
For example, to sort a collection of String based on the length and then case-insensitive natural ordering, the comparator can be composed using following code,
Comparator<String> cmp = Comparator.comparingInt(String::length)
.thenComparing(String.CASE_INSENSITIVE_ORDER);
It seems to be an clue but I don't know how to apply it to this simple example.
Edit 2
Let's say I want my List<String> to be sorted the following way:
First check: List.size() (the shorter is less than the larger one);
Second check if sizes match: comparing one by one each element of both Lists until finding one where the String.compareTo method returns 1 or -1.
How to do that with lambdas in a my compareTo method?
Edit 3
This does not duplicates this question because I want to know how to build a comparator of a class which contains a List<String> with Java 8 chaining Comparable calls.

So to compare the list, first you check the length, then you compare each item with same indexes in both list one by one right?
(That is [a, b, c] < [b, a, c])
Make a custom comparator for list return join of your list string:
Comparator<List<String>> listComparator = (l1, l2) -> {
if (l1.size() != l2.size()) {
return l1.size() - l2.size();
}
for (int i = 0; i < l1.size(); i++) {
int strCmp = l1.get(i).compareTo(l2.get(i));
if (strCmp != 0) {
return strCmp;
}
}
return 0; // Two list equals
};
Then you can compare using that custom comparator:
#Override
public int compareTo(MyClass other) {
return Comparator.comparing(MyClass::getSomeInt)
.thenComparing(Comparator.comparing(MyClass:: getSomeStrings , listComparator))
.compare(this, other);
}
If you want [a, b, c] = [b, a, c], then you have to sort those list first before comparing:
public String getSomeStringsJoined() {
return getSomeStrings().stream().sort(Comparator.naturalOrder()).collect(Collectors.joining());
}

Related

how to connect circular doubly-linked lists

Consider, I have given 2 items of the circular doubly-linked lists A and B. I want to implement a function which connects both of the lists.
This task is simple. However, I want to handle the case where A and B are the members of the same linked list. In this case it would just do nothing. Is it possible to implement it in O(1)? Do I need to check whether A and B are from the same list first? Or can I somehow magically swap/mix the pointers?
IMO it is not possible, but I'm unable to prove it.
thanks
You can. Being curious myself, I sketched an implementation in Java. Assuming a linked list as follows
public class CLinkedList {
class Node {
Node prev, next;
int val;
public Node(int v) {
val = v;
}
}
Node s;
public CLinkedList(Node node) {
s = node;
}
void traverse() {
if (s == null)
return;
Node n = s;
do {
System.out.println(n.val);
n = n.next;
} while (n != s);
}
...
}
a merging method would look like
void join(CLinkedList list) {
Node prev = list.s.prev;
Node sprev = s.prev;
prev.next = s;
sprev.next = list.s;
s.prev = prev;
list.s.prev = sprev;
}
which works just fine when the lists are different.
If they're not, all this does is just split the original list into two perfectly valid, different linked lists. All you should do is just join them again.
Edit: The join method joins (lol) two lists if they are different or (contrary to its name) splits the list if the nodes belong to the same list. Applying join twice thus has no effect, indeed. But you can make use of this property in other ways. The method below works fine:
public void merge(CLinkedList list) {
CLinkedList nList = new CLinkedList(s.next);
join(nList);
nList.join(list);
join(nList);
}
public static void main(String[] args) {
CLinkedList list = new CLinkedList(new int[] {1,2,3});
CLinkedList nlist = new CLinkedList(list.s.next);
list.merge(nlist);
list.traverse();
}
Still O(1) :) Keeping the small disclaimer - not the best quality code, but you get the picture.

Java8 StreamFilter within List

I have something like this:
// common code without java8-closures/stream-api (this works):
public static List<Person> getFilteredRes_OLD(List<Person>all, List<String> names){
List<Person> pos = new ArrayList<>();
for(Person e: all){
for(String n: names){
if(Person.isFemale(n).test(e)){
pos.add(e);
}
}
}
return pos;
}
public static Predicate<Person> isFemale(String test) {
return p -> p.getFirstName()!=null && p.getFirstName().equalsIgnoreCase(test);
}
Now, I want to use the new Stream-filter API in Java 8:
// JAVA 8 code (this works, but only for a specified filter-value):
public static List<Person> getFilteredRes_NEW(List<Person>all, List<String> names){
return all.stream()
// how can I put the list 'names" into the filter-Method
// I do not want to test only for 'Lisa' but for the wohle "names"-list
.filter( Person.isFemale("Lisa") )
.collect(Collectors.<Person>toList());
return pos;
}
My Question for getFilteredRes_NEW() is:
How can I put the list of 'names" into the filter-Method?
I do not want to test only for 'Lisa' but for the wohle "names"-list within the stream.
Here's, I think, the filter instruction you want:
.filter(person -> names.stream().anyMatch(
name -> Person.isFemale(name).test(person)))
For each person, it tests if there is at least one name N in the list of names for which the Person.isFemale(N).test(P) returns true.
It would be much simpler, and create less instances of Predicate, if you simply had a method
public boolean isFemale(Person p, String name) {
return p.getFirstName() != null && p.getFirstName().equalsIgnoreCase(test);
}
The code would become
.filter(person -> names.stream().anyMatch(name -> isFemale(person, name)))
You should also rename isFemale(), because it doesn't test at all if the person is female. It tests if a person has a given first name (ignoring the case).

Can Linq project an List of int to another list of class T

I have a list of int and I wonder if I can create another list of object T based on the previous list using Linq.
To simplify the issue:
I have a list of int like that: 1,2,3,4
and I expect to have (1,2), (2,4), (3,6), (4,8)
Normally, we can do that easily without Linq
public class T
{
int first;
int Second;
public T(int x, int y)
{
first = x;
Second = y;
}
}
class Program
{
static void Main(string[] args)
{
List<int> series = new List<int>() { 1,2,3,4 };
List<T> obj = new List<T>();
foreach (int item in series)
{
obj.Add(new T(item,item*2));
}
}
}
That worked perfectly.
But when I tried to use Linq
List<T> obj = series.Select(x=> {new T(x,x*2)}).ToList<T>();
I thought it would work but I got an error saying
Error 2 The type arguments for method 'System.Linq.Enumerable.Select<TSource,TResult>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,int,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
What have I done incorrectly? I am still a newbie (of probably a few month old) learning Linq :)
Get rid of the curly braces...
List<T> obj = series.Select(x=> new T(x,x*2)).ToList<T>();
When you write a lambda like:
x => x * 2
It's assumed that the right side is the return value. When you use curly braces, it's expecting you to actually use the return keyword, like this:
x => { return x * 2; }
When you don't, I bet it's assuming the lambda returns void.

how to sort the Vector containing objects using Blackberry API

I want to sort a vector which contains Object of following fields
public class CategoryListing {
String company_id;
String company_name;
double distance;
//setters and getters here
}
I populated the vector from webservice, now I want to sort that vector by distance, means I want to show nearest one. How can I sort the vector which contains objects?
None of the other answers are going to work for you on Blackberry as it doesn't support Generics. Blackberry uses older version of Java. Try the following code. It uses SimpleSortingVector
SimpleSortingVector sortVector = new SimpleSortingVector();
sortVector.setSortComparator(new Comparator() {
public int compare(Object o1, Object o2) {
CategoryListing o1C = (CategoryListing)o1;
CategoryListing o2C = (CategoryListing)o2;
return Double.toString((o1C.distance)).compareTo(Double.toString(o2C.distance));
}
});
//when you add elements to this vector, it is automatically sorted by distance
sortVector.addElement(new CategoryListing());
You can use Comparator.
Define a comparator which will sort on distance like below
public class DistanceComparator implements Comparator {
public int compare(Object o1, Object o2) {
return Double.valueOf(((CategoryListing) o1).distance)
.compareTo(((CategoryListing) o2).distance);// use getters
}
}
Sort vector using below sort method. Note As Arrays are present from 1.2 It is also present for blackberry.
public static void sort(Vector vector,Comparator comparator) {
Object[] array = new Object[vector.size()];
vector.copyInto(array);
Arrays.sort(array,comparator);
int i = 0;
Enumeration enumumeration = vector.elements();
while (enumumeration.hasMoreElements()) {
enumumeration.nextElement();
vector.insertElementAt(array[i++], i);
}
}

Sort Vector of objects in Scala

How can I sort a Vector of my objects in Scala? Is there some library sorting routines or do I have to write my own?
I have a class:
class Data2D(var x:Int, var y:Int)
and I am passing a vector of these to my function:
private def foo(data: Vector[Data2D]): Int = {
data:Vector sortedOnX = // ??
}
how can I sort the vector, based on the x-values of the Data2D objects?
In java I do:
Collections.sort(data, XComparator.INSTANCE);
where XComparator is:
enum XComparator implements Comparator<Data2D> {
INSTANCE;
#Override
public int compare(Data2D o1, Data2D o2) {
if (o1.getX() <= o2.getX()) {
return -1;
} else {
return 1;
}
}
}
private def foo(data: Vector[Data2D]): Int = data.sortBy(_.x)
See also the methods sortWith and sorted, as well as the methods provided by the Ordering object.

Resources