I have a simple class which is auto-generated and use to store responses from Retrofit. Anyway in the final step I would like to use row content, sort every element by position from highest to lowest and after sorting convert it to String[] with name only. How can I do that in the most efficient way?
public class RowModel implements Comparable<RowModel>{
private String name;
private double position;
public double getPosition() {
return position;
}
public void setPosition(float position) {
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public RowModel(String name, double position) {
this.name = name;
this.position = position;
}
}
After my search online I found this method to execute sorting but I'm not sure that the results are correct. And of course I still don't know how to convert sorted names to String[] at the final step:
#Override
public int compareTo(RowModel rowModel) {
double comparePosition = ((RowModel) rowModel).getPosition();
return (int) (this.position- comparePosition);
}
Your compareTo method won't work as you are comparing double values and it will fail when integral parts of two values are same (i.e. when comparing 1.5 & 1.2 your comparator will return 0 but it should return 1).
for that you can use Double.compare(d1, d2). you don't need to cast rowModel, too. Change your method as follow:
#Override
public int compareTo(RowModel rowModel) {
double comparePosition = rowModel.getPosition();
return Double.compare(this.position, comparePosition);
}
For Sorting you can use Collections.sort(rowModels).
To convert this sorted list to list of names, you can use Stream API.
Assuming you have Sorted List of RowModel with name rowModels.
List<String> names = rowModels.stream().map(RowModel::getName).collect(Collectors.toList());
If you want to convert this list to array,
String[] array = names.toArray(new String[names.size()]);
or directly,
String[] array = rowModels.stream().map(RowModel::getName).toArray(String[]::new);
Assuming a list of rows RowModel in a variable named rows, you can easily do that using the Stream API:
List<String> names = rows.stream().sorted()
.map(row -> row.getName())
.collect(Collectors.toList());
The intermediate step sorted() makes sure the stream is sorted, according to the Comparable implementation in your RowModel class, in this case.
Side note: Your compareTo implementation can be improved as it may be losing precision (casting double to int has the side effect of treating as equal two objects that aren't):
#Override
public int compareTo(RowModel rowModel) {
double comparePosition = ((RowModel) rowModel).getPosition();
double diff = this.position - comparePosition;
return diff == 0 ? 0 :
(diff > 0 ? 1 : -1);
}
List<RowModel> sortedModels = new ArrayList<>(models);
Collections.sort(sortedModels);
return sortedModels.toArray(new RowModel[0]);
Edit:
To actually return array of just names rather than whole RowModels, you could do something like this:
String[] result = new String[sortedModels.size()];
for (int i = 0; i < sortedModels.size(); i++) {
result.[i] = sortedModels.get(i).getName();
}
There is probably some shorter way to do this using Java 8 streams, but I'll leave that to someone who actually works with them.
Use util method of java.util.Collections class, i.e
Collections.sort(list)
If you want to sort custom object you can use
Collections.sort(List<T> list, Comparator<? super T> c)
see collections api
Related
I wan to create TreeSet() that will sort my elements with my predefined comparator. But the problem is when I give the comparator as a parameter to the constructor of the TreeSet(MyComparator), the TreeSet is not avoiding duplicates. Can I achieve sorting of the elements and avoiding duplicates?
The comparator looks like:
public static Comparator<Participant> byNameAndAge = (L, R) -> {
//check if they have the same code
if (L.code.equalsIgnoreCase(R.code))
return 0;
int res = L.name.compareToIgnoreCase(R.name);
if (res == 0)
res = Integer.compare(L.age, R.age);
return res;
};
You've misunderstood a few things. TreeSet does eliminate duplicates, with 'a duplicate' defined as 'any two elements for which your compare method returns 0'. No 2 such elements can both exist in a treeset. I'm sure your code doesn't work if you say so, but the code you pasted isn't the problem, nor is TreeSet's code.
A trivial example:
Comparator<String> byLength = (a, b) -> a.length() - b.length();
Set<String> set = new TreeSet<String>(byLength);
set.add("Hello");
set.add("World");
set.add("X");
set.add("VeryLong");
System.out.println(set);
> [X, Hello, VeryLong]
Note how 'World' disappeared, because the comparator says it is equal to Hello (they are both 5 length, a.length() - b.length() is returning 0, and 0 is 'equal, thus, eliminate the duplicate' according to treeset). In other words, your code as pasted would eliminate duplicates, the problem lies elsewhere.
This code is almost the same as yours.
Comparators chaining
public static void main(String[] args) {
// custom comparator
Comparator<Participant> byNameAndAge = Comparator
// first sorting by name ignoring case
.comparing(Participant::getName, String::compareToIgnoreCase)
// second sorting by age
.thenComparingInt(Participant::getAge);
// constructor with a comparator as a parameter
TreeSet<Participant> treeSet = new TreeSet<>(byNameAndAge);
treeSet.addAll(Set.of( // test data
new Participant("John", 25),
new Participant("Junior", 2),
new Participant("james", 31),
new Participant("john", 22)));
// output
treeSet.forEach(System.out::println);
//name=james, age=31
//name=john, age=22
//name=John, age=25
//name=Junior, age=2
}
static class Participant {
String name;
int age;
public Participant(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
#Override
public String toString() {
return "name=" + name + ", age=" + age;
}
}
I have an Android app with multiple input forms with multiple drop downs.
For these forms, the user can enter and exit the record multiple times before they commit the record.
Hence if they chose something on a drop down, exited the record, came back in again - they would expect to see their last entry already preselected in the drop down.
Here is an example of one of the many class types that drives a drop down list:
public class SART implements Serializable
{
private String Code;
private String Description;
public String getCode() {return Code;}
public void setCode(String Code) {this.Code = Code;}
public String getDescription() {return Description;}
public void setDescription(String Description) {this.Description = Description;}
}
So I take a known value and look up its position in the array list that drives the drop down and select
this line in the drop down.
Here is an example of how I do it:
int FindApplicationMethodPosition(ArrayList<SART> applicationMethods,String strExistingId)
{
int intSARTPosition = -1;
if (strExistingId !=null)
{
for(int i = 0; i <applicationMethods.size(); i++){
if(applicationMethods.get(i).getCode().equals(strExistingId))
{
intSARTPosition = i;
break;
}
}
}
return intSARTPosition;
}
I have about 30 different versions of this peppered through my code and I would like to try to call just one generic version.
int FindPositionGeneric(Object array, String strExistingId)
{
int intRC = -1;
intRC = IntStream.range(0, array.size())
.filter(i -> array.get(i).getCode().equals(strExistingId))
.findFirst()
.orElse(-1);
return intRC;
}
But of course the compiler does not like this at all.
Any suggestions please ?
But of course the compiler does not like this at all.
It doesn't know how to get the elements from array, nor how to get the code from an element in the array.
Pass in a List<T>, and a Function<T, String> to allow it to extract the code:
<T> int FindPositionGeneric(List<T> array, Function<T, String> codeFn, String strExistingId)
{
int intRC = -1;
intRC = IntStream.range(0, array.size())
.filter(i -> codeFn.apply(array.get(i)).equals(strExistingId))
.findFirst()
.orElse(-1);
return intRC;
}
Note that this is inefficient for non-RandomAccess lists (e.g. LinkedList). An alternative solution would be a ListIterator-based loop:
ListIterator<T> it = array.listIterator();
while (it.hasNext()) {
int idx = it.nextIndex();
String code = codeFn.apply(it.next());
if (code.equals(strExistingId)) {
return idx;
}
}
return -1;
If all the 30 versions of the class have the same getCode(), then create an interface (let it be MyInterface) and let all the classes implement this interface. Then update the method as follows:
int FindPositionGeneric(List<MyInterface> list, String strExistingId)
{
int intRC = IntStream.range(0, list.size())
.filter(i -> list.get(i).getCode().equals(strExistingId))
.findFirst()
.orElse(-1);
return intRC;
}
Also, since you have the orElse, no need to initialize intRC separately.
I need to sort below list of Details class objects with Java 8 Comparator
class Details{
String name;
String age;
}
in the order of Details class's names as below preference
1st--starting with Alphabets
2nd--starting with numeric
and 3rd-- starts with special character
Expected Result s/b:
sorted List of Details = sorted based on Details name irrespective of other parameters in the class
"Came"
"result"
"Result came"
"01 Result"
"02 Result"
"05 Result"
"# Came"
"# Result"
Collections.sort(List.o(details1,details2,details3),(d1,d2)->{
// got stuck here what to include to achieve the sort as per my requirement
return d1.getName().compareTo(d2.getName());
});
Here is Java 11(Just used var, that's it) code for you:
var a = List.of(details1, details2, details3)
.stream()
.sorted(Comparator.comparingInt((Details d) -> priority(d.getName())).thenComparing(Details::getName))
.collect(Collectors.toList());
If priority method is difficult to understand, you can refer #Eklavya's code
private static int priority(String str){
return Character.isAlphabetic(str.charAt(0))?1:Character.isDigit(str.charAt(0))?2:3;
}
You can define a custom priority like this
private static int priority(String str){
if (Character.isAlphabetic(string.charAt(0)))return 1;
if (Character.isDigit(string.charAt(0))) return 2;
return 3;
}
Then you can use in the compare function
Collections.sort(list, new Comparator<Project>() {
#Override
public int compare(Details o1, Details o2) {
int result = Integer.compare(priority(o1.name), priority(o2.name));
if (result != 0) return result;
return o1.name.compareTo(o2.name);
}
});
Using java 8 syntax
Collections.sort(list,Comparator.comparingInt(d -> priority(d.getName()))
.thenComparing(d-> d.getName()));
I want to create a table like structure in Java as shown in the image
Table structure
Though I am not an expert in Java, I have tried to implement it using Arraylist structure as follows:
List<List<Double>> dataList = new ArrayList<List<Double>>();
for(int x = 0; x < n; x++){
List<Double> tempList = new ArrayList<Double>();
dataList.add(tempList);
}
for(int y = 0; y < n; y++){
double execution = exectime[y];
double cost= cost[y];
dataList.get(y).add(execution);
dataList.get(y).add(cost);
}
for (int z=0;z<dataList.size();z++) {
Double v1=dataList.get(z).get(0);
Double v2=dataList.get(z).get(1);
System.out.println("ID"+z +" Execution time:" + v1 + "cost: " + v2);
}
Where the values of 'n', 'exectime[n]' and 'cost[n]' will be read from a file and 'n' is the total number of 'ids' that needs to be created.
After creating the table, I want to sort it based on the 'execution time' value and 'cost' value, both increasing and decreasing order. Please help me in this regards.
#snovelli's answer about using a class to encapsulate your data is a good point.
If you are using Java 8, you can easily create and chain comparators that use accessors.
For sorting a list of objects, it might look something like:
List<ExecutionTimeData> dataList = new ArrayList<>();
dataList.sort(Comparator
.comparing(ExecutionTimeData::getExecutionTime)
.thenComparing(ExecutionTimeData::getCost));
Sorting by execution time, followed by cost.
You could also use this to sort a List<List<Double>> if you really wanted to.
List<List<Double>> doubleListList = new ArrayList<>();
doubleListList.sort(Comparator
.comparing((List<Double> l) -> l.get(0))
.thenComparing(l -> l.get(1)));
Sorting by element 0 of the list, followed by element 1.
Or for sorting in reverse order:
List<ExecutionTimeData> dataList = new ArrayList<>();
dataList.sort(Comparator
.comparing(ExecutionTimeData::getExecutionTime).reversed()
.thenComparing(ExecutionTimeData::getCost).reversed());
Use Collections.sort() with Comparator.
However, you will loss your ID information because it is based on your index of the ArrayList. Therefore, if you use this method and want to keep you ID information, you need to add() ID to your ArrayList just like execution and cost.
Comparator<List<Double>> ORDER = new Comparator<List<Double>>() {
#Override
public int compare(List<Double> lhs, List<Double> rhs) {
if (lhs.get(1) < rhs.get(1)) return -1;
if (lhs.get(1) == rhs.get(1)) return 0;
return 1;
}
};
Collections.sort(dataList, ORDER);
In above code, your dataList will sorted with cost, because it is at the index 1 of the ArrayList.
However, the better way (in readability) is you put your column into a Class, not just a ArrayList. For example, you can create a Class like this:
class Information {
private int id;
private double execution;
private double cost;
Information(int id, double execution, double cost) {
this.id = id;
this.execution = execution;
this.cost = cost;
}
}
And implement static Comparator inside that class. It will improve the readability of your code.
I think You should use a Chained Comparator to implement sorting using multiple attributes. Because If you use a single Comparator Individually It will sort the data according to its own Compare() Method Implementation.
Better to Go with Chained Comparator which sort your data on multiple attribute ... Try the Following Link ==> Sorting a list by multiple attributes example
Use Collections as List < RegisterType > , RegisterType is created according to the type of registers present in the table (ex: with 3 double atributes)
Implement the Comparator interface Comparator< RegisterType >
Override the compare( RegisterType o1, RegisterType o2) method the way you want (define how to sort 2 elements of type RegisterType)
Inkove Collections.sort(List< RegisterType > list, ComparatorClass)
Then you will have your collection list sorted the way you want.
A table is a way to represent a list of objects, why not use a list of object then?
I think you want to have a SortedSet of a class that you could define as:
public class ExecutionTimeData{
private final long id;
private final long executionTime;
private final int cost;
public ExecutionTimeData(long id, long executionTime, int cost){
this.id = id;
this.executionTime = executionTime;
this.cost = cost;
}
/* Getters */
}
Then you will simply have an unsorted list like
List<ExecutionTimeData> unsortedList = new ArrayList<>();
As pointed out from #VikrantKashyap to order the list with both value and cost you then must implement a Chained Comparator
public class ExecutionTimeDataChainedComparator implements Comparator<ExecutionTimeData> {
private List<Comparator<ExecutionTimeData>> listComparators;
#SafeVarargs
public ExecutionTimeDataChainedComparator (Comparator<ExecutionTimeData>... comparators) {
this.listComparators = Arrays.asList(comparators);
}
#Override
public int compare(ExecutionTimeData etd1, ExecutionTimeData etd2) {
for (Comparator<ExecutionTimeData> comparator : listComparators) {
int result = comparator.compare(etd1, etd2);
if (result != 0) {
return result;
}
}
return 0;
}
}
And implement the comparators like this
public class ExecutionTimeDataCostComparator implements Comparator<ExecutionTimeData > {
#Override
public int compare(ExecutionTimeData a, ExecutionTimeData b) {
return b.getCost() > a.getCost()?-1:1;
}
}
public class ExecutionTimeDataExecutionComparator implements Comparator<ExecutionTimeData > {
#Override
public int compare(ExecutionTimeData a, ExecutionTimeData b) {
return b.getExecutionTime() > a.getExecutionTime()?-1:1;
}
}
And of course you can find out an easy way to invert the order by instantiating the comparators providing ASCENDING or DESCENDING order
I have a list of Strings. I want to evaluate each string based on a function that returns a double. Then I want the first 5 strings, based on their calculated values. If there are fewer than 5, I want all of them (in order). Let's say the strings are chemical compounds and the function computes the mass. The function is computationally expensive; I need to evaluate it once per string. (I'm just making up data here, though.)
H2O => 18.5
C12H11O22 => 109.1
HeNe => 32.0
H2SO4 => 54.37
HCl => 19.11
4FeO3 => 82.39
Xe6 => 281.9
The program should return the first five strings arranged in order by their respective values. For this sample data: H20, HCl, HeNe, H2SO4, 4FeO3. Actually, I don't really care about the order; I just need the five lowest in any order.
I thought about how I'd do this in Perl. It's just a few lines:
foreach $s (#str) {
$strmap{$s} = f($s);
}
#sorted = sort { $strmap{$a} <=> $strmap{$b} } keys %strmap;
return #sorted[0, 4]
But I need to do it in Java. And it's driving me crazy.
First I tried populating a HashMap<String, Double>, then using Collections.sort with a custom comparator, just like the Perl version. But scoping on the Comparator prevented it from referring to the HashMap to look up the values.
Then I tried a TreeMap<String, Double>, but it only sorts by key and no amount of coercing could get it to order the entries by value.
So I tried a TreeMap<Double, String>. It will discard entries with the same Double. However, the likelihood of having Strings that map to the same Double is low, so I pressed forward. Adding the entries to the TreeMap is no problem, but I ran into issues trying to extract the values from it.
TreeMap supplies a method called subMap, but its parameters are the keys that delimit the subset. I don't know what they are; I just want the first five of them. So I tried using the values method to get all the values out of the TreeMap, hoping they'd be in order. Then I can just get the first ten.
ArrayList<String> strs = (ArrayList<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));
Nope. Runtime error: cannot cast TreeMap$Values to ArrayList.
List<String> strs = (List<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));
Same. Runtime error trying to do the cast. OK, let's just assign to a Collection...
Collection<String> strs = treemap.values();
return new ArrayList<String>(strs.subList(0, 5));
Sorry, subList isn't a method of Collection.
Collection<String> strs = treemap.values();
ArrayList<String> a = new ArrayList<String>(strs);
return new ArrayList<String>(a.subList(0, 5));
Finally, something that works! But two extra data structures just to get the first five elements? And I'm not too wild about using Double as the key for TreeMap.
Is there a better solution?
I don't think you'll get more compact than the three lines above, not in Java.
Apart from that, I have the impression that a Map as a data structure is the wrong choice in the first place, since you do not seem to need by-string lookups (UNLESS you want in some way deal with multiple occurences of strings, but you didn't say so). An alternative approach would be to declare your own comparable data record class:
private static class Record implements Comparable<Record> {
// public final fields ok for this small example
public final String string;
public final double value;
public Record(String string, double value) {
this.string = string;
this.value = value;
}
#Override
public int compareTo(Record other) {
// define sorting according to double fields
return Double.compare(value, other.value);
}
}
// provide size to avoid reallocations
List<Record> records = new ArrayList<Record>(stringList.size());
for(String s : stringList)
records.add(new Record(s, calculateFitness(s));
Collections.sort(records); // sort according to compareTo method
int max = Math.min(10, records.size()); // maximum index
List<String> result = new ArrayList<String>(max);
for(int i = 0; i < max; i++)
result.add(records.get(i).string);
return result;
This is now much more verbose than the three lines above (this is Java, after all), but also includes the code that would be required to insert the key/value pairs into the map.
Would something like the following work for you?
Note that I've assumed you don't require the double value other than to sort the data.
public static void main(String[] args) throws Exception {
List<String> data = new ArrayList<>(Arrays.asList("t", "h", "i", "s", "i", "s", "t", "e", "s", "t", "d", "a", "t", "a"));
Collections.sort(data, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
double o1Value = evaluate(o1);
double o2Value = evaluate(o2);
return Double.compare(o1Value, o2Value);
}
});
List<String> result = data.subList(0, 10); // Note the end point is exclusive
for (String s : result) {
System.out.println(s);
}
}
private static double evaluate(String s) {
return s.codePointAt(0); // Nonsense, I know
}
This example prints:
a
a
d
e
h
i
i
s
s
s
Why don't you just create a class to combine the String, Double and function that does the calculation - something like:
public Thing implements Comparable<Thing>
{
private String s;
private Double d;
public Thing(String s)
{
this.s = s;
this.d = calculateDouble(s);
}
public String getString()
{
return this.s;
}
public Double getDouble()
{
return this.d;
}
public int compareTo(Thing other)
{
return getDouble().compareTo(other.getDouble());
}
public Double calculateDouble(String s)
{
...
}
}
Then all you need is a List<Thing>, Collections.sort and List.subList.