This question already has answers here:
In Java how do you sort one list based on another?
(23 answers)
Closed 2 years ago.
I am trying to sort custom objects on some custom order but I am not able to. I can sort if objects are String or integer. I have posted some detailed description on code below. Thanks for any help.
Private static final List<String> places = Arrays.asList(“Switzerland”, “America”, “Romania”, “Chad”, "Australia");
//this list is fixed and always needs to maintain this order
Map<String, String> countrFromDB = countryDAO.getAllCOuntriesFromDB();
List<Country> sortCountry= new ArrayList<>();
for(Map.Entry<String, String> entry : countrFromDB.entrySet() ){
Country c = new Country(entry.getKey(), entry.getValue());
sortCountry.add(c);
if(places.contains(countrFromDB.getKeyValue())){
sortCountry.add(c.getKeyValue());
}
}
for(Country data:sortCountry){
System.out.println(data.getKeyValue());
}
I get America, Chad, Australia, Switzerland, Romania. However, I need to maintain order like in
places = Switzerland, America, Romania, Chad, Australia
You have to use indexOf in the comparator
final List<String> places = Arrays.asList("Switzerland", "America", "Romania", "Chad", "Australia");
.....
.....
.....
Collections.sort(sortCountry, new Comparator<Country>(){
public int compare(Country o1, Country o2){
return places.indexOf(o1.getValue()) - places.indexOf(o2.getValue());
}
});
for(Country data:sortCountry){
System.out.println(data.getValue());
}
Why not construct the list in the order you want in the first place, so you don't need to sort it separately?
List<Country> sortCountry= new ArrayList<>();
for(String place : places){
if (countrFromDB.containsKey(place)) {
Country c = new Country(place, countrFromDB.get(place));
sortCountry.add(c);
}
}
Related
I have a list of custom object,
public class Assignmentsdata {
String assignmentId;
String teacherId;
String groupName;
String sectionId;
String levelId;
String startTime;
}
ArrayList<Assignmentsdata> list = new ArrayList<>();
lets say there are 20 elements in that list.
Now I want to get the output which is a hashmap of startTime as a key and the Value would be a new HashMap of GroupID and a list of Assignments of those that had the same groupName.
OutPut Example
HashMap<startTime,HasMap<groupName,List> hashMap = new HashMap();
a little more insight about the problem: First I want to categorise based on startTime(Month) then i want to categorise based on groupName, Thanks in advance.
I have successfully categorised based on group name and created a map through below code:
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
After that I am lost on how to categorise this hashmap based on the startDate and create a hashmap that would look like the above hashmap in the output heading.
your code may throw a NullPointerException at the first if branch
if (hashMap.size()>0)
{hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
the map.size()>0 doesnt means the Value of GroupName has put a new ArrayList already.
the anwser of using loop should like this
Map<String, Map<String, List<Assignmentsdata>>> map = new HashMap<>();
for (Assignmentsdata assignmentsdata : list) {
if (!map.containsKey(assignmentsdata.getStartTime())) {
map.put(assignmentsdata.getStartTime(), new HashMap<>());
}
Map<String, List<Assignmentsdata>> startTimeMap = map.get(assignmentsdata.startTime);
if (!startTimeMap.containsKey(assignmentsdata.getGroupName())) {
startTimeMap.put(assignmentsdata.getGroupName(), new ArrayList<>());
}
startTimeMap.get(assignmentsdata.groupName).add(assignmentsdata);
}
or you could use the java stream().collect(Collectors.groupingBy()) api to get the result easily
Map<String, Map<String, List<Assignmentsdata>>> result = list.stream()
.collect(Collectors.groupingBy(Assignmentsdata::getStartTime,Collectors.groupingBy(Assignmentsdata::getGroupName)));
I am answering my own question as I solved it if anyone has a better answer please passed your answer aswell, ill accept another answer suitable and efficient answer.
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
if (hashMap.get(assignmentsdataArrayList.get(i).getGroupName())==null){
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else{
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
// above part is already in the question. the second part i looped through the hashMap then the list once again, and checking if list and map entry have same group name, then made the startdate key that indexed element from the list.
HashMap<String, Map.Entry<String, ArrayList<Assignmentsdata>>> hashMapHashMap = new HashMap<>();
for (var entry : hashMap.entrySet()){
for( int j = 0; j<assignmentsdataArrayList.size();j++ ){
if (assignmentsdataArrayList.get(j).getGroupName()==entry.getKey()){
hashMapHashMap.put(assignmentsdataArrayList.get(j).getStartTime(),entry);
}
}
hashMapHashMap.put(entry.getValue().get())
}
This question already has answers here:
Why do I need to override the equals and hashCode methods in Java?
(31 answers)
Closed 2 years ago.
So I have an ArrayList with objects that have name, id, salary etc. And a Queues with another ArrayList objects, model, year etc.
I created a HashMap and used the ArrayList objects as keys and the queues as values, associating each queue for a object in the arraylist.
The thing is, I have to list all the values for a determined key.
I would like to know how can I return all the values of a hashmap depending on the name value of the object.
For example this my map:
{Mech [Name = Ella McCarthy , ID = 1]=[Car [model=Civic, year=2010, fix=flat tyres], Car [model=Audi A3, year=2012, fix=something broken]],
Mech [Name = Josh Reys , ID = 1]=[Car [model=Cruze, year=2014, fix=something broken], Car [model=Impala, year=1990, fix=something broken]]}
Is there any way of returning the value if the name in the object in the key equals to Ella McCarthy?
Next code may comprehensive for you:
public class MapExample {
private static final String DETERMINED_KEY = "Ella McCarthy";
Queue<Car> queue = new PriorityQueue<>();
Map<Mech, Queue<Car>> map = new HashMap<>();
Queue<Car> getValuesByNameInKeyObjectWithStreams() {
Queue<Car> cars = map.entrySet()
.stream()
.filter(mapEntry -> mapEntry.getKey().getName().contentEquals(DETERMINED_KEY))
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(); // Throw exception if did't find according value. Or return another result with orElse(result)
return cars;
}
Queue<Car> getValuesByNameInKeyObjectBeforeJava8() {
for (Map.Entry<Mech, Queue<Car>> entry : map.entrySet()) {
String mechName = entry.getKey().getName();
if (mechName.equals(DETERMINED_KEY)) {
return entry.getValue();
}
}
// Throw exception or return another result
throw new RuntimeException("If didn't find exception");
}
}
class Mech {
String name;
public String getName() {
return name;
}
}
class Car {
String value;
}
If you prefer functional style and use java 8 or higher, peek getValuesByNameInKeyObjectWithStreams method.
This question already has answers here:
Comparator sort matching String at first, and rest using default sorting order
(2 answers)
Closed 2 years ago.
I have a list of items (users id)
List<String> userUid= Arrays.asList("uid1", "uid3", "uid5", "uid2", "uid4", "uid0");
How can I put for example "uid2" at the top of the list, and then sort the list? So the new list would be:
uid2, uid0, uid1, uid3, uid4, uid5.
I tried with no success userUid.sort(Comparator.comparing("uid2"::equals).reversed());
The problem with this is that it will show at the top of the list the last element of the old list.
To explain more I want to make a list of users and I want to show at the top of this list the user that is logged in. And then sort the list alphabetically.
You can write a custom comparator for this:
Comparator<String> comparator = (o1, o2) -> {
if (o1.equals("uid2")) return -1;
if (o2.equals("uid2"))return 1;
return o1.compareTo(o2);
};
Collections.sort(userUid,comparator);
or you can do like this:
List<String> res = userUid.stream().sorted()
.filter(u -> !u.equals("uid2"))
.collect(ArrayList::new,
(l, s) ->{if (l.isEmpty())l.add("uid2");l.add(s);},
List::addAll );
Here are the steps:
Remove the user's id from the list of names.
Sort the names
Add the user's id to the front of the list
Something like this:
List<String> userUid= Arrays.asList("uid1", "uid3", "uid5", "uid2", "uid4", "uid0");
List<String> sortedIds = Stream.concat(Stream.of("uid2"), userUid.stream()
.filter(id -> !"uid2".equals(id)) // in java-11 use Predicate::not
.sorted())
.collect(Collectors.toList());
Implement your comparator such that, when the element equals the currentUserUid, it is smallest, otherwise compare them alphabetically.
public class CustomSort {
public static void main(String[] args) {
List<String> userUid = Arrays.asList("uid1", "uid3", "uid5", "uid2", "uid4", "uid0");
final String currentUserUid = "uid2";
userUid.sort((uid1, uid2) -> {
if (uid1.equals(uid2)) {
return 0;
}
if (uid1.equals(currentUserUid)) {
return -1;
}
if (uid2.equals(currentUserUid)) {
return 1;
}
return uid1.compareTo(uid2);
});
System.out.println(userUid);
}
}
I want to filter a single array into parts. Suppose I have an ArrayList of String :
Array1 = ["2015-01-06","2015-04-06",
"2016-06-06","2016-01-06",
"2016-05-06","2017-02-06",
"2017-04-06","2017-03-06",
"2015-03-06","2016-04-06",
"2016-02-06","2015-05-06",
"2015-01-06","2016-06-06"]
I want it to filter in new arrays according to their years, so that the output will look like :
arrayA = ["2015-01-06","2015-04-06","2015-03-06","2015-05-06","2015-01-06"]
arrayB = ["2016-06-06","2016-01-06","2016-05-06","2016-04-06","2016-02-06","2016-06-06"]
arrayC = [""2017-02-06","2017-04-06","2017-03-06""]
The arrays are based on years now. I don't know the proper way for accomplishing this task.
The question was edited to include the Android tag, making this inapplicable for the OP since Android doesn't support Java 8 yet, I'll leave it in case it helps someone not using Android though.
Using the Stream API, you can easily build a Map<Integer, List<String>> where each key is a year. You can use groupingBy(classifier) where the classifier extracts the year from the date. In this case, the date is parsed with LocalDate.parse but you could easily extend that by giving your own formatter.
public static void main(String[] args) {
String[] array = {"2015-01-06","2015-04-06",
"2016-06-06","2016-01-06",
"2016-05-06","2017-02-06",
"2017-04-06","2017-03-06",
"2015-03-06","2016-04-06",
"2016-02-06","2015-05-06",
"2015-01-06","2016-06-06"};
Map<Integer, List<String>> map =
Arrays.stream(array)
.collect(Collectors.groupingBy(s -> LocalDate.parse(s).getYear()));
// or a simple s -> Integer.valueOf(s.substring(0, s.indexOf('-'))) in this case
}
You can then access the list you want from that map.
This will create an ArrayList each year
ArrayList<String> array1 = new ArrayList<String>();
Map<String, List<String>> mapForYear = new TreeMap<String, List<String>>();
for(String date : array1)
{
String year = date.substring(0,4);
if(!mapForYear.containsKey(year))
mapForYear.put(year, new ArrayList<String>());
mapForYear.get(year).add(date);
}
That's easy if you use java 8 and Stream API. I wrote the following piece of code:
public List<String> getListByYear(String[] array, int year) {
return Arrays.stream(array)
.filter(s -> s.contains(Integer.toString(year)))
.collect(Collectors.toList());
}
As to the question, there is such solution:
for (String s : array) {
int key = LocalDate.parse(s).getYear();
List<String> value = map.get(key);
map.put(key, value == null
? new ArrayList<String>() { { add(s); } }
: new ArrayList<String>(value) { { add(s); } }
);
}
The same result as #Tunaki provided, but a less pretty. If Java 8 is not supported, it will be as the alternative as the most compact solution.
Output is here:
{
2016 = [2016-06-06, 2016-01-06, 2016-05-06, 2016-04-06, 2016-02-06, 2016-06-06],
2017 = [2017-02-06, 2017-04-06, 2017-03-06],
2015 = [2015-01-06, 2015-04-06, 2015-03-06, 2015-05-06, 2015-01-06]
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
suppose I have a "journal article" class which has variables such as year, author(s), title, journal name, keyword(s), etc.
variables such as authors and keywords might be declared as String[] authors and String[] keywords
What's the best data structure to search among a group of objects of "journal paper" by one or several "keywords", or one of several author names, or part of the title?
Thanks!
==========================================================================
Following everybody's help, the test code realized via the Processing environment is shown below. Advices are greatly appreciated! Thanks!
ArrayList<Paper> papers = new ArrayList<Paper>();
HashMap<String, ArrayList<Paper>> hm = new HashMap<String, ArrayList<Paper>>();
void setup(){
Paper paperA = new Paper();
paperA.title = "paperA";
paperA.keywords.append("cat");
paperA.keywords.append("dog");
paperA.keywords.append("egg");
//println(paperA.keywords);
papers.add(paperA);
Paper paperC = new Paper();
paperC.title = "paperC";
paperC.keywords.append("egg");
paperC.keywords.append("cat");
//println(paperC.keywords);
papers.add(paperC);
Paper paperB = new Paper();
paperB.title = "paperB";
paperB.keywords.append("dog");
paperB.keywords.append("egg");
//println(paperB.keywords);
papers.add(paperB);
for (Paper p : papers) {
// get a list of keywords for the current paper
StringList keywords = p.keywords;
// go through each keyword of the current paper
for (int i=0; i<keywords.size(); i++) {
String keyword = keywords.get(i);
if ( hm.containsKey(keyword) ) {
// if the hashmap has this keyword
// get the current paper list associated with this keyword
// which is the "value" of this keyword
ArrayList<Paper> papers = hm.get(keyword);
papers.add(p); // add the current paper to the paper list
hm.put(keyword, papers); // put the keyword and its paper list back to hashmap
} else {
// if the hashmap doesn't have this keyword
// create a new Arraylist to store the papers with this keyword
ArrayList<Paper> papers = new ArrayList<Paper>();
papers.add(p); // add the current paper to this ArrayList
hm.put(keyword, papers); // put this new keyword and its paper list to hashmap
}
}
}
ArrayList<Paper> paperList = new ArrayList<Paper>();
paperList = hm.get("egg");
for (Paper p : paperList) {
println(p.title);
}
}
void draw(){}
class Paper
{
//===== variables =====
int ID;
int year;
String title;
StringList authors = new StringList();
StringList keywords = new StringList();
String DOI;
String typeOfRef;
String nameOfSource;
String abs; // abstract
//===== constructor =====
//===== update =====
//===== display =====
}
Use a HashMap<String, JournalArticle> data structure.
for example
Map<String, JournalArticle> journals = new HashMap<String, JournalArticle>();
journals.put("keyword1", testJA);
if (journals.containsKey("keyword1")
{
return journals.get("keyword1");
}
you can put your keywords as the key of String type in this map, however, it only supports "exact-match" kind of search, meaning that you have to use the keyword (stored as key in the Hashmap) in your search.
If you are looking for " like " kind of search, I suggest you save your objects in a database that supports queries for "like".
Edit: on a second thought, I think you can do some-kind-of "like" queries (just like the like clause in SQL), but the efficiency is not going to be too good, because you are iterating through all the keys in the HashMap whenever you do a query. If you know regex, you can do all kinds of queries with modification of the following example code (e.g. key.matches(pattern)):
List<JournalArticle> results = null;
for (String key : journals.keySet())
{
if (key.contains("keyword")) /* keyword has to be part of the key stored in the HashMap, but does not have to be an exact match any more */
results.add(journals.get(key));
}
return results;
For simple cases you can use a Multimap<String, Article>. There's one in Guava library.
For larger amounts of data Apache Lucene will be a better fit.
I would create a map from a keyword (likewise for author, or title, etc.), to a set of JournalArticles.
Map<String, Set<JournalArticle>> keyWordMap = new HashMap<>();
Map<String, Set<JournalArticle>> authorMap = new HashMap<>();
When you create a new JournalArticle, for each of its key words, you'd add that article to the appropriate set.
JournalArticle ja = new JournalArticle();
for(String keyWorld : ja.getKeyWords())
{
if(keyWordMap.containsKey(keyWorld) == false)
keyWordMap.put(keyWorld, new HashSet<JournalArticle>());
keyWordMap.get(keyWorld).add(ja);
}
To do a look up, you'd do something like:
String keyWord = "....";
Set<JournalArticle> matchingSet = keyWordMap.get(keyWord);