This question already has answers here:
How to sort an arraylist of objects java?
(6 answers)
Closed 9 years ago.
I have a problem.
I want to sort Strings from txt file by the numbers of characters in String
For example
Input:
aaa
a
aa
Output:
a
aa
aaa
I created Collection that contain strings by alphabet & created collection that contain number of String characters, but i can't understand
How I can sort by the numbers of characters in String
public class SortingFile {
public static void main(String[] args) throws IOException {
try{
File inputFile=new File("c:/a.txt");
Reader r=new FileReader(inputFile);
BufferedReader br=new BufferedReader(r);
List <String> list = new LinkedList<String>();
List <Integer> listLength= new LinkedList<Integer>();
String line=br.readLine();
list.add(line);
while (line!=null){
line=br.readLine();
list.add(line);
}
int arrsize=(list.size())-1;
System.out.println("line array size= "+arrsize);
list.remove(arrsize); //delete last element (he is null )
System.out.println("Before sorting by alphabet: "+list);
Collections.sort(list);//sorting by alphabet
System.out.println("After sorting by alphabet: " +list);
for (int i=0;i!=list.size();i++){ //add string lenght to collection
String a=list.get(i);
int aa=a.length();
listLength.add(aa);
}
System.out.println("lineLength:"+listLength);
Collections.sort(listLength); // sotring by asc
System.out.println("lineLength2:"+listLength);
br.close();
}catch (FileNotFoundException e1){
System.out.println("File ''a.txt'' Not Found :(");
e1.printStackTrace();
}
}
}
Try, with following Comparator
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
});
Use Collections.sort(java.util.List, java.util.Comparator) which takes an additional Comparator argument.
That allows you to change the way things are sorted.
Collections.sort has an overloaded method where you can give a comparator. Code a comparator where you will compare the length of the strings and return whatever is greater or smaller (depending upon whether you want ascending or descending order). then just invoke your Collections.sort(myListOfString,myComporator); and the result would be a list of strings ordered by length.
Pass comparator to your Collection.sort(list,yourSorter) method and use whatever logic you want to use in it.
Collections.sort(list, sortAccordingToLength);
static Comparator<String> sortAccordingToLength= new Comparator<String> {
public int compare(String a, String b) {
return a.length()-b.length();
}
});
Related
Each line in my movies.txt file loooks like;
id,title,rating,year,genre (rating is an integer from 1 to 5)
1,The Godfather,5,1972,Drama
2,Pulp Fiction,4,1994,Crime
I want to list the movies sorted by their rating. I was able to sort the ratings but I don't know how to preserve the connection between ratings and lines and I couldn't sort the lines based on ratings.
BufferedReader b = new BufferedReader(new FileReader("movies.txt"));
String line = null;
int[] ratings = null;
int i;
try{
while((line = b.readLine()) != null)
{
String[] data = line.split(",");
int rating = Integer.parseInt(data[2]);
ratings[i] = rating;
i++;
}
b.close();
Arrays.sort(ratings);
}catch(IOException ex){
System.out.println("Error");
}
Is there any way I can do this by using arrays or something else, without creating a class and using a Movie object?
Instead of using only data[2], we store the whole result of each line and sort by index[2] (as we need to leave it as string, the comparator is sorting not as Integer but as String)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
BufferedReader b = new BufferedReader(new FileReader("movies.txt"));
String line = null;
List<String[]> lines = new ArrayList();
int i;
try {
while ((line = b.readLine()) != null) {
String[] data = line.split(",");
lines.add(data);
}
b.close();
lines.sort(new CustomComparator());
lines.forEach(o -> System.out.println(Arrays.toString(o)));
} catch (IOException ex) {
System.out.println("Error");
}
}
public static class CustomComparator implements Comparator<String[]> {
#Override
public int compare(String[] o1, String[] o2) {
return o1[2].compareTo(o2[2]);
}
}
}
Create all lines in the list and sort with stream:
List<String> lines = new ArrayList<String>();
lines.add("1,The Godfather,5,1972,Drama");
lines.add("2,Pulp Fiction,4,1994,Crime");
lines.add("2,Pulp Fiction,33,1994,Crime");
lines.add("2,Pulp Fiction,1,1994,Crime");
List<Object> collect = lines.stream().sorted(new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return Integer.parseInt(o1.split(",")[2]) - Integer.parseInt(o2.split(",")[2]);
}
}).collect(Collectors.toList());
Then put sorted collection to file.
Use a CSV Parser to load the data into a List, then sort the list.
E.g. if using Apache Commons CSV, you can do it like this:
// Load data into memory
List<CSVRecord> records = new ArrayList<>();
try (Reader in = Files.newBufferedReader(Paths.get("movies.txt"));
CSVParser parser = CSVFormat.RFC4180.parse(in)) {
parser.forEach(records::add);
}
// Sort data
records.sort(Comparator.comparingInt(r -> Integer.parseInt(r.get(2))));
// Print result
try (CSVPrinter printer = CSVFormat.RFC4180.printer()) {
printer.printRecords(records);
}
Output
2,Pulp Fiction,4,1994,Crime
1,The Godfather,5,1972,Drama
If you just want to sort the lines by the 3rd element you should first read the lines, then sort them and write them back (that's what I assume you want to do). A naive approach would be to write a comparator that splits each line, parses the 3rd element to an int and compares the values, e.g. like this:
List<String> lines = ... //read, e.g. using Files.readAllLines(pathToFile)
Collections.sort(lines, Comparator.comparing( line -> {
String[] elements = lines.split(","); //split
return Integer.parseInt(elements[2]); //parse and return
}));
This, however, is very inefficient so you might try and use a couple of optimizations:
split the lines into arrays when reading and join them when writing
sort "integer" strings with a little trick: sort by length and then lexically
Example:
List<String[]> splitLines = ... //read and split
Collections.sort(splitLines,
Comparator.comparing( (String[] e)-> e[2].length()) //help the compiler with the lambda parameter type, at least in my tests it couldn't infer the type otherwise
.thenComparing( e -> e[2] ));
splitLines.forEach( elements -> writeToFile(String.join(",", elements));
This could even be done in a single stream:
Files.lines(pathToFile)
.map(line -> line.split(",")) //split each line
.sorted(Comparator.comparing( (String[] e)-> e[2].length()) //sort by length and then by natural order
.thenComparing( e -> e[2] ))
.map( elements -> String.join(",", elements) ) //join back to a single string
.forEach(line -> writeToFile(line)); //write to line
This is based on a couple of assumptions:
all lines have the same format
no title contains a comma or the split is able to handle escaped values
lines don't have leading or trailing whitespace
integers don't have leading zeros
How does the sorting "trick" work?
Basically it first sorts integer strings by order of magnitude. The higher the length the larger the number should be, i.e. "2" is shorter than "10" and thus smaller.
Within the same order of magnitude you'd then sort normally taking the order of digits into account. Thus "100" is smaller than "123" etc.
Final notes:
It would still be better to actually convert lines into Movie elements, especially if you have more complex requirements or data.
Use a proper CSV parser instead of regex and basic string operations.
Would Collections.sort() work in sorting by Make in a Car object Array List? I'm getting no error messages after adding the null there, but my goal is to sort them by Make, specifically, but I'm not entirely sure how to go about doing that.
public void readingFromFile(String file) throws FileNotFoundException //an object array that takes in string files
{
try {
File myFile = new File(file); //converts the parameter string into a file
Scanner scanner = new Scanner(myFile); //File enables us to use Scanner
String line = scanner.nextLine(); //reads the current line and points to the next one
StringTokenizer tokenizer = new StringTokenizer(line, ","); //tokenizes the line, which is the scanned file
//counts the tokens
while (tokenizer.hasMoreTokens()){
String CarMake = tokenizer.nextToken(); //since car is in order by make, model, year, and mileage
String CarModel = tokenizer.nextToken();
int CarYear1 = Integer.parseInt(tokenizer.nextToken());
int CarMileage1 = Integer.parseInt(tokenizer.nextToken()); //converts the String numbers into integers
Car cars = new Car(CarMake, CarModel, CarYear1, CarMileage1); //since the car has a fixed order
arraylist.add(cars); //add the cars to the unsorted array
}
scanner.close(); //close the scanner
} catch (FileNotFoundException f){
f.printStackTrace();
return;
}
arraylist2.addAll(arraylist);
Collections.sort(arraylist2, null);
}
Use the streaming API:
sorted = arrayList2.stream().sorted(Comparator.comparing(Car::getMake));
Since Java 8 the List has a sort method inherited by Collection. Additionally you can use the Comparator class to create a comparator very easy:
arraylist2.sort(Comparator.comparing(Car::getMake));
If you want to use multiple Parameters for your sort you can easily append them:
arraylist2.sort(Comparator.comparing(Car::getMake)
.thenComparing(Car::getYear)
// ...
);
If you are using a Java Version below Java 8 you have to implement the sort logic yourself in an Comparator or use an external library:
Collections.sort(arraylist2, new Comparator<Car>() {
#Override
public int compare(Car a, Car b) {
return a.getMake().compareTo(b.getMake());
}
});
For multiple parameters it would look like the following:
Collections.sort(arraylist2, new Comparator<Car>() {
#Override
public int compare(Car a, Car b) {
int compareMake = a.getMake().compareTo(b.getMake());
if (compareMake != 0) {
return compareMake;
}
return a.getYear() - b.getYear();
}
});
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);
}
}
}
In this program I need to display an array list from an external file in descending order. Whenever I run the program though, I still get the same order of the original list. I just need help with the descending order part. I utilized the Collections methods to accomplish this task but I don't think I fully understand exactly what is going on whenever I call upon Collections, it just spits out the array list as brought in by the first array call. Any help would be greatly appreciated. I placed 4 stars at the end and beginning of the code in question.
import java.io.*;
import java.util.*;
public class ioStafford {
public static void revOrder(String x[])
{
}
public static void main(String args[])
{
try(BufferedReader fr1 = new BufferedReader(new FileReader("myImport.txt")))
{
//Create a new file for the reverse output if it doesn't exist
File f1 = new File("myOutput.txt");
//Code for new file creation
if(!f1.exists())
{
f1.createNewFile();
}
//Initialize string variables
String type;
//Array List to hold text file
ArrayList<String> names = new ArrayList<String>();
//Add text file contents to the array list
while((type = fr1.readLine()) != null)
{
names.add(type);
}
//Display array list
System.out.println("Below is the list of animals with a comma and in the original order:");
System.out.println(names);
****//Display information in descending order
Collections.sort(names, Collections.reverseOrder());
System.out.println(names);****
//Convert array list to string and replace commas
String fornames = names.toString().replace("," , " ");
//Display altered information
System.out.println("Here is the list with the commas removed:");
System.out.println(fornames);
}
catch(FileNotFoundException e)
{
System.out.println("Please utilize the file named myImport.txt please!");
}
catch(IOException e)
{
}
}
}
Try this one in a place of
Collections.sort(names, Collections.reverseOrder());
:->
Collections.sort(names, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
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());