Hello everyone I have a code using an arraylist, these are the test inputs to be added. But after I use the sort method. The output is not the one I expected.
ArrayList<String> test= new ArrayList<>();
test.add("2,2,17");
test.add("5,4,24 ");
test.add("8,1,11");
test.add("19,0,0");
test.add("2,3,21");
test.sort(null);
Output :
19,0,0
2,2,17
2,3,21
5,4,24
8,1,11
My desired out put should be :
2,2,17
2,3,21
5,4,24
8,1,11
19,0,0
Is there a way to sort "19,0,0" to be at the end, or any number to be add to make it the end of the arrayList?
You'll want to use Collections.sort, something like this:
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
int s1int = Integer.parseInt(s1.substring(0, s1.indexOf(",")));
int s2int = Integer.parseInt(s2.substring(0, s2.indexOf(",")));
return s1int - s2int;
}
});
You can use Collections.sort()
https://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator).
And define a Comparator to compare the objects in the list.
In order for the strings to be sorted alphabetically rather than numerically, you will need to implement a comparator that converts the strings to integers for the comparison. You can then use this comparator with Collections.sort() to sort your list.
A better option would be to store your integers as integers in a 2D array rather than as strings (or some kind of nested list if the dimensions are not known up-front); however, I'd need to know more about how the data is created and used before uniformly proclaiming this to e the solution.
A possible flexible solution for Strings of various 'lengths', i.e. a different number of integers separated by commas.
Example list
2,2,17
5,4,24
19,0,2
8,1,11
19,0,1,2
19,0,1,4
2,3,21
2
Result after sorting
2
2,2,17
2,3,21
5,4,24
8,1,11
19,0,1,2
19,0,1,4
19,0,2
Code
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortExample {
public static void main(String[] args) {
List<String> test = new ArrayList<>();
test.add("2,2,17");
test.add("5,4,24");
test.add("19,0,2");
test.add("8,1,11");
test.add("19,0,1,2");
test.add("19,0,1,4");
test.add("2,3,21");
test.add("2");
Collections.sort(test, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
String[] split1 = s1.split(",");
String[] split2 = s2.split(",");
final int indicesToCheck = Math.min(split1.length, split2.length);
int result = 0;
int i = 0;
while (result == 0 && i < indicesToCheck) {
result = Integer.compare(Integer.parseInt(split1[i]),
Integer.parseInt(split2[i]));
i++;
}
return result == 0 ? Integer.compare(split1.length, split2.length) : result;
}
});
for (String s : test) {
System.out.println(s);
}
}
}
Related
I have a collection of strings in an array like this:
ArrayList<String> collection = new ArrayList<>();
That stores:
collection: ["(,0,D=1", "(,1,D=2", "),2,D=2", "),3,D=1", "(,4,D=1", "(,5,D=2", "),6,D=2", "),7,D=1"]
I have a lot of d=1 and d=2, as you can see. How do I organize this from 1 first to 2? I tried to use a for loop but the list can contain an infinite number of d=x's. Can you help me organize?
Also, please help me so I don't change the ORDER of any numbers. Example:
collection: ["(,0,D=1", "),3,D=1", "(,4,D=1", "),7,D=1", "(,1,D=2", "),2,D=2", "(,5,D=2", "),6,D=2"]
So like, every parentheses will be aligned.
I should note that collection[0] = "(,0,D=1"
You should use a class for the items, not a string, e.g. Class Item {char c; int i; int depth;} and ArrayList. Then you can easily sort the list with a custom Comparator.
You can implement your own Comparator to do the sorting. A Comparator is a sorting algorithms that you define for your application which written in programming language. Give Collections.sort() a Comparator basically you teach Java how you want to sort the list. And it will sort the list for you.
This implementation is based on the following assumptions:
The comparison will only take effect on the first D=x pattern, subsequent will be ignored.
Element is sorted in ascending order base on x.
Elements do not have D=x will be placed at the back
class DeeEqualComparator implements Comparator<String> {
private static final String REGEX = "D=([0-9])+";
#Override
public int compare(String s1, String s2) {
// find a D=x pattern from the element
Matcher s1Matcher = Pattern.compile(REGEX).matcher(s1);
Matcher s2Matcher = Pattern.compile(REGEX).matcher(s2);
boolean s1Match = s1Matcher.find();
boolean s2Match = s2Matcher.find();
if (s1Match && s2Match) {
// if match is found on s1 and s2, return their integer comparison result
Integer i1 = Integer.parseInt(s1Matcher.group(1));
Integer i2 = Integer.parseInt(s2Matcher.group(1));
return i1.compareTo(i2);
} else if (s1Match) {
// if only s1 found a match
return -1;
} else if (s2Match) {
// if only s2 found a match
return 1;
} else {
// if no match is found on both, return their string comparison result
return s1.compareTo(s2);
}
}
Test run
public static void main(String[] args) {
String[] array = {
// provided example
"(,0,D=1", "(,1,D=2", "),2,D=2", "),3,D=1", "(,4,D=1", "(,5,D=2", "),6,D=2", "),7,D=1"
// extra test case
, "exception-5", "exception-0", "D=68" };
List<String> list = Arrays.asList(array);
Collections.sort(list, new DeeEqualComparator());
System.out.print(list);
}
output
[(,0,D=1, ),3,D=1, (,4,D=1, ),7,D=1, (,1,D=2, ),2,D=2, (,5,D=2, ),6,D=2, D=68, exception-0, exception-5]
I have an ArrayList as defined below:
List<String> where = new ArrayList<String>();
where.add("1 Kg");
where.add("500 gram");
where.add("5 Kg");
When I display this list, values shown are shown as:
1 Kg
500 gram
5 Kg
I want it to be displayed as given below:
500 gram
1 Kg
5 Kg
How should I sort it.
You need a Comparator where you can write your comparison logic.
See the following implementation.
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> where = new ArrayList<String>();
where.add("5 Kg");
where.add("500 gram");
where.add("1 Kg");
Collections.sort(where, new MassComparator());
for(String mass : where) {
System.out.println(mass);
}
}
public static class MassComparator implements Comparator<String> {
#Override
public int compare(String weight1, String weight2) {
double val1 = Double.parseDouble(weight1.replace("gram", "").replace("Kg", "").trim());
double val2 = Double.parseDouble(weight2.replace("gram", "").replace("Kg", "").trim());
if (weight1.contains("gram")) {
val1 *= .001;
}
if (weight2.contains("gram")) {
val2 *= .001;
}
int result = 0;
if (val1 < val2) {
result = -1;
} else if (val1 > val2) {
result = 1;
}
return result;
}
}
}
Input
List<String> where = new ArrayList<String>();
where.add("500 gram");
where.add("2 Kg");
Output
500 gram
2 Kg
If you really want to sort String representations of values instead of harmonizing the values in your data (e.g. all in grams) and sort them in the natural order of the values only, you'll need quite some work.
Use a Comparator<String> - see here for API. You'll inject this in an invocation of Collections.sort when sorting your List (API here).
In your compare method, parse two things out of each String through regular expressions: a number (real or integer, depends on your data) and a measurement unit (possibly based on an map defining all variants for gram, kilogram, etc.)
Then compare the measurement units (possibly using another Comparator<String>!) and convert the parsed numbers to their values for a single unit (likely grams, etc.)
Finally compare the harmonized numerical values after converting them to actual numbers (e.g. Integers or Doubles, etc.) - using their natural order this time
"Optionally", handle all edge cases: null or empty values, Strings not containing a numerical representation or measurement unit, ambiguous values, etc. etc.
Store your values as Double as shown below
List<Double> where = new ArrayList<Double>();
where.add(0.5);
where.add(1);
where.add(5);
You can apply sorting on above list,
also at the time of retrieving you can use 0.5 kg instead of 500 grams if your app requirement allows it.
Mr #11thdimension has already given a perfect working solution. I think you can also use Java 8, if you want. Basically the same idea but less code.
List<String> where = new ArrayList<String>();
where.add("1 Kg");
where.add("500 gram");
where.add("5 Kg");
Collections.sort(where, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
double a = (Double.parseDouble(o1.replace("gram","").replace("Kg","").trim()))*(o1.contains("gram")?0.001:1);
double b = (Double.parseDouble(o2.replace("gram","").replace("Kg","").trim()))*(o2.contains("gram")?0.001:1);
return Double.compare(a,b) ;
}
});
where.stream().forEach(System.out::println);
just use index and for cycle,
for(int i=0; i<where.size(); i++){
System.out.println(where.get(i));
}
This question already has answers here:
Sorting alphanumeric strings java
(4 answers)
Closed 8 years ago.
My input -
List<String> parameterNames => [value0, type1, type0, name1, value1, name0]
I use Collections.Sort
Collections.sort(parameterNames)
I get the answer like this
[name0, name1, type0, type1, value0, value1]
I want to sort and get the list like this
[name0,type0,value0,name1,type1,value1]
will I be able to do this in Java??
Write a custom Comparator, and pass it's instance to the sort method:
Comparator<String> myComparator = new Comparator<String>() {
public int compare(String str1, String str2) {
// get the number at the end, and compare on the basis of that number
// And then do the string comparison on substring before number
}
};
Collections.sort(parameterNames, myComparator);
When you use Collections.sort(), you can pass a Comparator to implement a custom method for checking what's higher and what's lower in search order.
It is better to use custom Comparator interface. If you faced problem to use Comparator than try to use following code:
List<String> revList= new ArrayList<>();
List<String> parameterNames=..//[value0, type1, type0, name1, value1, name0]
for (String string : parameterNames) {
revList.add(new StringBuilder(string).reverse().toString());//reverse the word
}
Collections.sort(revList);// Sort reverse word.
for (String string : revList) {
System.out.println(new StringBuilder(string).reverse().toString());
// Again reverse to get desired output.
}
Output: name0,type0,value0,name1,type1,value1
You need to implement your own Comparator with this logic.
Assuming all your values are of the format stringNUMBER, here's a shot at the implementation:
/**
* Compares two {#link String}s of the format stringNUMBER. Assumption: There is a single numeric part to the string,
* always at the end.
*/
public class TrailingNumberComparator implements Comparator<String> {
#Override
public int compare(String o1, String o2) {
int cmp = o1.substring(getStrartNumberIndex(o1)).compareTo(o2.substring(getStrartNumberIndex(o2)));
if (cmp != 0) {
return cmp;
}
return o1.compareTo(o2);
}
private static int getStrartNumberIndex(String s) {
for (int i = 0; i < s.length(); ++i) {
if (Character.isDigit(s.charAt(i))) {
return i;
}
}
return s.length();
}
}
You'll then be able to call Collections.sort(parameterNames, new TrailingNumberComparator());
Is there any way to sort a vector numerically?(i wanna sort the number before the first ; (semicolon)
I need let's say this (it's a vector with 4 String/components)
[
7394;dasd;dasda;dasda;5;3
2222;dasdasd;das;true;7;4;dsda;60
6660;dsada;dasasd;true;6;3
2345;dasdsagfd;das;true;7;4;gfgfdgd;60
]
to become this
[
2222;dasdasd;das;true;7;4;dsda;60
2345;dasdsagfd;das;true;7;4;gfgfdgd;60
6660;dsada;dasasd;true;6;3
7394;dasd;dasda;dasda;5;3
]
or this [3123;dasdas;31;31 1115;das;31;312 4412;sdf;31;42]
to [1115;das;31;312 3123;dasdas;31;31 4412;sdf;31;42]
(im sorting 3123, 1115, and 4412 numerically but i still keep the things after)
I've thought of converting each components to a string and then doing something like:
int count;
for(int i=0;i<string_component1.length();i++){
if(Character.isDigit(string_component1.charAt(i)){
count = i;
break;
}
}
and then with substring i would take the part i want, put it on a string, convert it to an int, then i would take the first one(lowest), use vector contains to find in which components its in and take this components to put it on a new vector at the first position. and so on with the others components
but i think its too much code for nothing and it wouldn't work since the vector size can be 3 or 50.
Is there any way to sort a vector numerically?(i want to sort the number before the first ; (semicolon) )
The general pattern to sort a java.util.Vector is to implement a Comparator and pass it to the Collections.sort() method. All the logic for sorting order can then be put into the compare() method of the Comparator. In your case, it could look like this:
public static void main(String[] args) {
String[] input = {"7394;dasd;dasda;dasda;5;3", "2222;dasdasd;das;true;7;4;dsda;60",
"6660;dsada;dasasd;true;6;3", "2345;dasdsagfd;das;true;7;4;gfgfdgd;60"};
Vector<String> vec = new Vector<>();
vec.addAll(Arrays.asList(input));
System.out.println("Input : " + vec);
Collections.sort(vec, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
int i1 = Integer.valueOf(o1.split(";")[0]);
int i2 = Integer.valueOf(o2.split(";")[0]);
return i1 - i2;
}
} );
System.out.println("Result: " + vec);
}
Output:
Input : [7394;dasd;dasda;dasda;5;3, 2222;dasdasd;das;true;7;4;dsda;60, 6660;dsada;dasasd;true;6;3, 2345;dasdsagfd;das;true;7;4;gfgfdgd;60]
Result: [2222;dasdasd;das;true;7;4;dsda;60, 2345;dasdsagfd;das;true;7;4;gfgfdgd;60, 6660;dsada;dasasd;true;6;3, 7394;dasd;dasda;dasda;5;3]
Here's the elegant way of doing it using Collections.sort() with a Comparator:
Vector<String> vector;
Collections.sort(vector, new Comparator<String>() {
public int compare(String s1, String s2) {
return getInt(s1) - getInt(s2);
}
int getInt(String s) {
return Integer.parseInt(s.replaceAll("(\\d+).*", "$1"));
}
});
I couldn't understand your sorting order, but you can sort a collection using a Collection.sort(),
You can use Collection.sort() to sort your list and implement a custom Comparator to order elements the way you want.
If you strings have a fix pattern you could do something like:
int indexOfSemi = string_component.indexOf(";")
With this you have the first semicolon.
And then with:
String myNumber = string_component.substring(0,indexOfSemi-1)
And now you have your number which you must convert to int.
Do this in a Comparator class and you have your comparing mechanism.
I have an array of filenames and need to sort that array by the extensions of the filename. Is there an easy way to do this?
Arrays.sort(filenames, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
// the +1 is to avoid including the '.' in the extension and to avoid exceptions
// EDIT:
// We first need to make sure that either both files or neither file
// has an extension (otherwise we'll end up comparing the extension of one
// to the start of the other, or else throwing an exception)
final int s1Dot = s1.lastIndexOf('.');
final int s2Dot = s2.lastIndexOf('.');
if ((s1Dot == -1) == (s2Dot == -1)) { // both or neither
s1 = s1.substring(s1Dot + 1);
s2 = s2.substring(s2Dot + 1);
return s1.compareTo(s2);
} else if (s1Dot == -1) { // only s2 has an extension, so s1 goes first
return -1;
} else { // only s1 has an extension, so s1 goes second
return 1;
}
}
});
For completeness: java.util.Arrays and java.util.Comparator.
If I remember correctly, the Arrays.sort(...) takes a Comparator<> that it will use to do the sorting. You can provide an implementation of it that looks at the extension part of the string.
You can implement a custom Comparator of Strings. Make it sort them by the substring after the last index of '.'. Then pass in the comparator and your array into
Arrays.sort(stringArray, yourComparator);
// An implementation of the compare method
public int compare(String o1, String o2) {
return o1.substring(o1.lastIndexOf('.')).compareTo(o2.substring(o2.lastIndexOf('.'));
}
Comparators are often hard to get exactly right, and the comparison key has to be generated for every comparison which for most sorting algorithms mean O(n log n). Another approach is to create (key, value) pairs for each item you need to sort, put them in a TreeMap, and then ask for the values as these are sorted according to the key.
For instance
import java.util.Arrays;
import java.util.TreeMap;
public class Bar {
public static void main(String[] args) {
TreeMap<String, String> m2 = new TreeMap<String, String>();
for (String string : Arrays.asList(new String[] { "#3", "#2", "#1" })) {
String key = string.substring(string.length() - 1);
String value = string;
m2.put(key, value);
}
System.out.println(m2.values());
}
}
prints out
[#1, #2, #3]
You should easily be able to adapt the key calculation to your problem.
This only calculates the key once per entry, hence O(n) - (but the sort is still O(n log n)). If the key calculation is expensive or n is large this might be quite measurable.
Create a Comparator and compare the string extensions. Take a look at the following
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Comparator.html
Then pass in your List of strings to Arrays.sort(List, Comparator)
Create your own Comparator that treats the strings as filenames and compares them based on the extensions. Then use Arrays.sort with the Comparator argument.
String DELIMETER = File.separator + ".";
List<String> orginalList = new CopyOnWriteArrayList<>(Arrays.asList(listOfFileNames));
Set<String> setOfuniqueExtension = new TreeSet<>();
for (String item : listOfFileNames) {
if (item.contains(".")) {
String[] split = item.split(DELIMETER);
String temp = "." + split[split.length - 1];
setOfuniqueExtension.add(temp);
}
}
List<String> finalListOfAllFiles = new LinkedList<>();
setOfuniqueExtension.stream().forEach((s1) -> {
for (int i = 0; i < orginalList.size(); i++) {
if (orginalList.get(i).contains(s1)) {
finalListOfAllFiles.add(orginalList.get(i));
orginalList.remove(orginalList.get(i));
i--;
}
}
});
orginalList.stream().filter((s1) -> (!finalListOfAllFiles.contains(s1))).forEach((s1) -> {
finalListOfAllFiles.add(s1);
});
return finalListOfAllFiles;
If you just want to group the files by their extension and do not care about the actual alphabetical order, you can use this:
I think the simplest thing you can do that also works when the filenname does not have a "." is to just reverse the names and compare them.
Arrays.sort(ary, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
String r1 = new StringBuffer(o1).reverse().toString();
String r2 = new StringBuffer(o2).reverse().toString();
return r1.compareTo(r2);
}
});
Its a shame that java's string does not even have a reverse().