Sorting of ArrayList<Track> - java

I want to sort ArrayList according to artist's name I have used comparator interface but I'm not able to sort the list. So kindly help me to solve the problem. The track data will be read from a file Trackdump. The file would contain one track data per line in the format TITLE/ARTIST/RATING/BPM
Here is the code:
import java.io.*;
import java.util.*;
public class MusicLibrary {
ArrayList<Track> songList = new ArrayList<Track>();
public static void main(String args[]) {
new MusicLibrary().go();
}
public void go() {
System.out.println("go");
getTracks();
System.out.println("Before Sorting:");
System.out.println(songList);
Collections.sort(songList);
System.out.println("Sorted according to Artist's name:");
System.out.println(songList);
}
void getTracks() {
System.out.println("gt");
File file = new File("TrackDump.txt");
try{
BufferedReader readr = new BufferedReader(new FileReader(file));
String line = null;
System.out.println(readr);
while ((line = readr.readLine()) != null) {
System.out.println(line);
addSong(line);
}
}catch(Exception e){
e.printStackTrace();
}
}
void addSong(String lineToParse) {
String[] tokens = lineToParse.split("/");
Track nextSong = new Track(tokens[0], tokens[1], tokens[2], tokens[3]);
songList.add(nextSong);
System.out.println(songList);
}
}
class Track implements Comparator<Track>
{
String title;
String artist;
String rating;
String bpm;
public int compare(Track o1, Track o2) {
return o1.getArtist().compareTo(o2.getArtist());
}
public Track(String a, String t, String r, String b) {
title = t;
artist = a;
rating = r;
bpm = b;
}
public boolean equals(Object aSong) {
return this.equals(aSong);
}
public String getArtist() {
return artist;
}
public String getBpm() {
return bpm;
}
public String getRating() {
return rating;
}
public String getTitle() {
return title;
}
public String toString() {
return title + "-" + artist;
}
}
Trackdump:
Title1/Artist1/8/320
Title2/Artist2/10/48
T5/A7/10/120
Title4/A7/9/240
T7/Artist5/7/320
Title6/Artist6/3/240
T9/A7/1/550
T6/Artist8/5/120
T1/Artist9/5/290
Song2/A0/5/320
Song5/A8/10/320
Song1/A2/6/290

You have to implement Comparable class to your Track class. Not Comparator. Then override compareTo() method. It would look like this:
public class Track implements Comparable<Track> {
// Variables, constructor, getters, setters ...
#Override
public int compareTo(Track other) {
return this.getArtist().compareTo(other.getArtist());
}
}
Finally sort with Collections.sort();

You need to implement the Comparable interface and then you can use Collections.sort().
class Track implements Comparable<Track> {
String title;
String artist;
String rating;
String bpm;
#Override
public int compare(Track other) {
return this.getArtist().compareTo(other.getArtist());
}
...
In theory it would work too when implementing Comparator but then you have to pass a Track object into Collections.sort() to act as the Comparator. But that is a rather weird way of doing it so better use the solution above.
Collections.sort(songList, new Track(null, null, null, null));

Related

Implement binarySearch() in ArrayList by String object Java

How can I use Binary Search with an ArrayList?
Here are elements of the ArrayList:
public class DictionaryElements implements
Comparable<DictionaryElements>, Comparator<DictionaryElements>{
private String word;
private String translation;
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public String getTranslation() {
return translation;
}
public void setTranslation(String translation) {
this.translation = translation;
}
public DictionaryElements() {
}
public DictionaryElements(String word, String translation) {
this.word = word;
this.translation = translation;
}
#Override
public String toString() {
return word + " - " + translation;
}
#Override
public int compareTo(DictionaryElements dictionary) {
return this.word.compareTo(dictionary.word);
}
#Override
public int compare(DictionaryElements wordOne, DictionaryElements wordTwo) {
return wordOne.getWord().compareTo(wordTwo.getWord());
}
}
Than I sorted a list here:
public class DictionarySorter {
ArrayList<DictionaryElements> dictionaryList = new ArrayList<>();
public DictionarySorter(ArrayList<DictionaryElements> dictionaryList) {
this.dictionaryList = dictionaryList;
}
public ArrayList<DictionaryElements> getSortedByWord() {
Collections.sort(dictionaryList);
return dictionaryList;
}
}
And here I tried to imply Binary Search:
public class Main {
public static void main(String[] args) {
DictionaryElements dictionaryElements = new DictionaryElements();
ArrayList<DictionaryElements> dictionaryList = new ArrayList<>();
DictionarySorter dictionarySorter = new
DictionarySorter(dictionaryList);
boolean found = true;
dictionaryList();
Scanner scanner = new Scanner(System.in);
System.out.println("Write one word in English:");
String wordInEnglish = scanner.nextLine();
int index = Collections.binarySearch(dictionaryList, wordInEnglish);
if (found) {
//code here.
}
else {
System.out.println("Sorry, i didn't find " + wordInEnglish + " ;(");
}
scanner.close();
}
public static void dictionaryList() {
ArrayList<DictionaryElements> dictionaryList = new ArrayList<>();
dictionaryList.add(new DictionaryElements("Apple", "Apfel"));
dictionaryList.add(new DictionaryElements("Pear", "Birne"));
dictionaryList.add(new DictionaryElements("Orange", "Orange"));
DictionarySorter dictionarySorter = new DictionarySorter(dictionaryList);
ArrayList<DictionaryElements> sortedDictionaryList = dictionarySorter.getSortedByWord();
for (DictionaryElements dictionary : sortedDictionaryList) {
System.out.println(dictionary);
}
}
}
Error says:
The method binarySearch(List<? extends Comparable<? super T>>, T) in the type Collections is not applicable for the arguments (ArrayList, String)
What did I missed and how can I fix this?
If you have a look at the method declaration for Collections.binarySearch the comparator implemented must be of the same type as the key being passed in.
Your DictionaryElements extends Comparable of type DictionaryElements type but the key you are passing in is of type String.
You'll need pass a DictionaryElement as the key instead:
DictionaryElements key = new DictionaryElements(wordInEnglish, translation);
int index = Collections.binarySearch(dictionaryList, key);
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#binarySearch(java.util.List,%20T)
You have a list of DictionaryElements objects, and are looking for a String.
That's like me handing you a bag of apples and asking: Hey, find me this pear.
The compiler is helping you out and preventing you from writing this code, as it would make no sense.

sorting linked list in alphabetical order

I want to order nodes' chosen string variables. this is an homework due to tomorrow.
public void sortSongName() {
DefaultSongs sortedList = new DefaultSongs();
int temp= Integer.MAX_VALUE;
Song curr=root;
Song hold = null;
while(root.nextSong != null) {
if(curr.getSongName().charAt(0)<hold.getSongName().charAt(0)) {
hold=curr;
curr=root.nextSong;
}else {
curr=root.nextSong;
}
sortedList.createSong(root.nextSong.getSongName(),root.nextSong.getBandName() , root.nextSong.getDuration());
deleteSong(root.nextSong.getSongName());
sortSongName();
}
}
Assuming your song class look something like this
public class Song {
private String name;
public String name() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
And the DefaultSongs class is just a repo with a list of Songs
public class DefaultSongs {
private final List<Song> songList;
public DefaultSongs() {
this.songList = new ArrayList<>();
}
public List<Song> songList() {
return songList;
}
}
Simplest way would be to use java stream
public void sortSongsByName(){
songList.stream().sorted(Comparator.comparing(Song::name));
}
The simplest way is to use Collections.sort();
For example:
List<String> songs = Arrays.asList("Bam","Cam", "Am","Dam");
Collections.sort(songs);
System.out.println(songs);
This will give you the list in alphabetical order.

Object-oriented design for comment subject object

I'm trying to figure out the best way to design a class, which encapsulates JSON-derived comments. Each comment is targeted at a particular subject, either a file as a whole or a line of a file. Here's an example comment:
{
"text":"This is my favorite line!",
"path":"My file.txt",
"line":42
...
}
If the subject is a file as a whole, line is null.
I want the Comment class to have a subject() method, but I'm not sure the best way to design the CommentSubject class. Here's what I have so far:
import javax.json.JsonObject;
class Comment {
private final JsonObject json;
private final CommentSubject subject;
public JsonObject json() { return json; }
public CommentSubject subject() { return subject; }
public Comment(JsonObject json) {
...
this.json = json;
subject = json.isNull("line") ? new FileSubject(this) :
new LineSubject(this);
...
}
...
}
abstract class CommentSubject {
enum SubjectType {
FILE, LINE
}
public abstract SubjectType type();
public abstract String path();
protected abstract Comment comment();
}
class FileSubject extends CommentSubject {
private final Comment comment;
private final String path;
public FileSubject(Comment comment) {
this.comment = comment;
path = comment.json().getString("path");
}
public FileSubject(CommentSubject subject) {
this(subject.comment());
}
#Override public SubjectType type() { return SubjectType.FILE; }
#Override public String path() { return path; }
#Override protected Comment comment() { return comment; }
...
}
class LineSubject extends CommentSubject {
private final Comment comment;
private final String path;
private final int line;
public LineSubject(Comment comment) {
this.comment = comment;
path = comment.json().getString("path");
line = comment.json().getInt("line");
}
public LineSubject(CommentSubject subject) {
this(subject.comment());
}
#Override public SubjectType type() { return SubjectType.LINE; }
#Override public String path() { return path; }
#Override protected Comment comment() { return comment; }
public int line() { return line; }
...
}
Client code could look like this:
doSomething(CommentSubject subject) {
if (subject.type() == SubjectType.LINE) {
LineSubject line = new LineSubject(subject);
...
}
...
}
However, I don't like the fact that my current design requires a new LineSubject object in the client code: subject and line are identical in the example above, so the new object creation seems like a waste of space. Further, in order to pass a CommentSubject object to another CommentSubject constructor, as in the client code above, all subjects need to be backed by a comment accessible by the comment() method. I also don't know what I think about the SubjectType enum.
What I want is for Comment to have a subject() method and to be able to distinguish file and line subjects. Are there better designs out there?
If the only difference between a file comment and a line comment is that the file comment does not have a line number, you can fold the class hierarchy to a single class, and make the line number optional (i.e. returning an Integer rather than an int). This would let client programs distinguish between file and line comments, because file comments would return null for the line number:
public class CommentSubject {
private final Integer line;
private final String path;
private final String comment;
public String path() { return path; }
public Integer line() { return line; }
public Comment comment() { return comment; }
public static CommentSubject forFile(String p, String c) {
return new CommentSubject(p, null, c);
}
public static CommentSubject forLine(String p, int i, String c) {
return new CommentSubject(p, i, c);
}
private CommentSubject(String p, Integer i, String c) {
path = p;
line = i;
comment = c;
}
}
The client would be able to write something like this:
doSomething(CommentSubject subject) {
Integer optLine = subject.line();
if (optLine != null) {
int line = optLine.intValue();
...
}
...
}
If you prefer to avoid conditional dispatch in the client, you could take a visitor-like approach, and have the CommentSubject call back the processor of your comments, like this:
interface CommentProcessor {
void onFileComment(String path, String comment);
void onLineComment(String path, int line, String comment);
}
public class CommentSubject {
private final Integer line;
private final String path;
private final String comment;
public void process(CommentProcessor p) {
if (line != null) {
p.onLineComment(path, line.intValue(), comment);
} else {
p.onFileComment(path, comment);
}
}
public static CommentSubject forFile(String p, String c) {
return new CommentSubject(p, null, c);
}
public static CommentSubject forLine(String p, int i, String c) {
return new CommentSubject(p, i, c);
}
private CommentSubject(String p, Integer i, String c) {
path = p;
line = i;
comment = c;
}
}
Note how the comment, path, and line are hidden inside CommentSubject. The only way to access them now is to pass an instance of CommentProcessor, which would receive a callback for the appropriate type of CommentSubject.

Sorting a list of objects based on different data members in java

I have this class:
public class Friend {
private String name;
private String location;
private String temp;
private String humidity;
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
I want to sort a List based on name, location, temp and humidity based on user input.
EDIT:The user specifies by which data member the sorting has to be done.
What is the easiest way to do this?
Thank you.
Because you want to sort them by four different standards, implementing Comparable does not make sense. In this case, you may find that creating different Comparators for each sort-by parameter. However, you could implement Comparable for the most logical sort-by field, such as name. Otherwise, comparators are the way to go.
public class FriendNameComparator extends Comparator<Friend> {
// assuming both are non-null for code simplicity; you may wish to change that
public int compare(Friend f1, Friend f2) {
return f1.getName().compareTo(f2.getName());
}
}
public class FriendLocationComparator extends Comparator<Friend> {
// assuming both are non-null for code simplicity; you may wish to change that
public int compare(Friend f1, Friend f2) {
return f1.getLocation().compareTo(f2.getLocation());
}
}
// and so forth
Then, you can use the sort function of the Collections utility class to sort by the given comparator.
Collections.sort(friendsList, new FriendNameComparator()); // sorts by name
Collections.sort(friendsList, new FriendLocationComparator()); // sorts by location
// etc
Java has a static function called Collections.sort(List, Comparator) which sorts a (generified) List of objects given a custom Comparator which, given two objects of the same type, determines which one is ordered before the other.
Your task is to write a function which creates a Comparator which orders the objects based on its arguments and the user specified sort order. For example:
public Comparator<Friend> getComparator(final String sortBy) {
if ("name".equals(sortBy)) {
return new Comparator<Friend>() {
#Override int compare(Friend f1, Friend f2)
return f1.getName().compareTo(f2.getName());
}
};
} else if ("location".equals(sortBy)) {
return new Comparator<Friend>() {
#Override int compare(Friend f1, Friend f2)
return f1.getLocation().compareTo(f2.getLocation());
}
};
} else if ("temp".equals(sortBy)) {
// ...
} else {
throw new IllegalArgumentException("invalid sort field '" + sortBy + "'");
}
}
List list=new ArrayList();
Use If else if for each criteria:
if(location ){
Collections.sort(list, new Comparator () {
public int compare(YourObject o1, YourObject o2) {
return o1.getLocation().compareTo(o2.getLocation());
}
});
}
} else if(temp ){
........
}
.......

Java Question Linked List objects

I have the following piece of code :
Essentially the number of methods should remain the same as in the code and I need to extract a string from an element of the linkedlist of Objects of type emp_struct.. How do I do it?
import java.util.*;
import java.io.*;
class a1 {
static LinkedList l1;
private emp_struct input() throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
emp_struct obj = new emp_struct();
obj.emp_id = br.readLine();
obj.name = br.readLine();
obj.salary = Double.parseDouble(br.readLine());
obj.dept = br.readLine();
try{
search(obj);
}catch(Exception e){
System.out.println(e);
obj = input();
}
return obj;
}
boolean search(emp_struct obj)
{
int lastIndex = l1.lastIndexOf(l1);
int begIndex = 0;
for(begIndex =0;begIndex<lastIndex;begIndex++)
{
Object chkCase = l1.get(begIndex);
String chk = chkCase.getEmpID();
if(chk.equals(obj.emp_id));
throw new DuplicateEntryException("Duplicate entry found");
}
return true;
}
public static void main(String args[]) throws IOException
{
l1 = new LinkedList();
}
}
class DuplicateEntryException extends Exception {
String detail;
DuplicateEntryException(String a)
{
detail = a;
}
public String toString()
{
return "User Defined Exception : "+detail;
}
}
class emp_struct {
public String emp_id;
public String name;
public double salary;
public String dept;
public String getEmpID()
{
return emp_id;
}
public String toString()
{
return emp_id+"\t"+name+"\t"+salary+"\t"+dept;
}
}
In your search method, if you find the value, you're throwing an exception. If you don't find the value, you return true. This doesn't seem like the best approach.
If you find the value, shouldn't you return true, then if it makes it through the array without finding it, shouldn't you return false?
This line
Object chkCase = l1.get(begIndex);
should be
emp_struct chkCase = (emp_struct)l1.get(begIndex);
among other things...

Categories

Resources