I have a HashMap, i have sorted the categories and put it in a list ie initially the categories were : - A,B,C,D and after sorting it is D,C,B,A and i've added it to the List.
I want to display questions based on the sorted order of category i.e
Display all questions with category :- D
then Display all questions with category :- C and so on.
here is what I've tried:-
List<Category> list = Arrays.asList(Category.values());
List<Question> list1 = new ArrayList<>();
list1.addAll(questionList);
Collections.sort(list, new Comparator<Category>() {
#Override
public int compare(Category o1, Category o2) {
return o2.ordinal() - o1.ordinal();
}
});
System.out.println("Categories" +list);
Map< List<Category>,List<Question>> map = new HashMap<>();
map.put(list, list1);}}
boolean ty = list1.containsAll(list1);
if(ty==true){
out.println(list1.get(0).getQuestion()) ;}
i want my output to be like this:-
D: what is your name?
how are you?
C: another question1?
another question2?
B: another question3?
another question4?
I want to display questions based on the sorted order of category i.e
Display all questions with category :- D then Display all questions
with category :- C and so on.
To perform your need, questions must be related to a category.
You have two ways of doing :
using a comparator (as #Surace done) to sort all questions in a final list.
creating a map (list of questions as value and category as key)
Comparator is more concise and it is rather a good idea but in your case it has a drawback, it doesn't keep the category associated to each question while you want it in your rendering :
i want my output to be like this:-
D: what is your name? how are you?
C: another question1? another question2?
B: another question3? another question4?
You may retrieve the information with category information stored in the question but it forces you to do rather clumsy processing during iteration because the category is not a external information but a computed information that you have to search in another object.
By creating a map which associates questions by category, you just need to iterate to render the information and in more general way you may perform any additional processing for each iteration of category.
Here the code :
public static void main(String[] args) {
// create your questions
List<Question> questionsInput = new ArrayList<>();
questionsInput.add(new Question("question 1 For A?", Category.A));
questionsInput.add(new Question("question 2 For A?", Category.A));
questionsInput.add(new Question("question 1 For A?", Category.B));
questionsInput.add(new Question("question 2 For A?", Category.B));
Map<Category, List<Question>> map = associateQuestionByCat(questionsInput);
// display info
for (Entry<Category, List<Question>> entry : map.entrySet()) {
System.out.print("cat " + entry.getKey() + ":");
for (Question q : entry.getValue()) {
System.out.print(q.getQuestion());
}
System.out.println("");
}
}
public static Map<Category, List<Question>> associateQuestionByCat(List<Question> questions ) {
Map<Category, List<Question>> questionsByCategory = new TreeMap<>(Collections.reverseOrder());
for (Question q : questions) {
final Category currentCat = q.getCat();
List<Question> questionsForCurrentCat = questionsByCategory.get(currentCat);
if (questionsForCurrentCat == null) {
questionsForCurrentCat = new ArrayList<>();
questionsByCategory.put(currentCat, questionsForCurrentCat);
}
questionsForCurrentCat.add(q);
}
return questionsByCategory;
}
}
I think this will give your expected output.
Collections.sort(list, new Comparator<Category>() {
#Override
public int compare(Category o1, Category o2) {
// o1.getCategoryName() is A or B or C or D
return o1.getCategoryName().compareTo(o2.getCategoryName());
}
});
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())
}
How to group all the Objects in a List with the same Object property? Without mentioning the Object property value.
Model Class:
public class Item {
private String id;
private String name;
private String team
}
List<item> items = new ArrayList();
I have tried this:
items.stream().filter(item -> "Elites".equals(item.team)).collect(Collectors.toList());
But this requires passing the team name as a parameter.
How can we group the items without specifying a team value?
And Making a HashMap with Key as the item. team and value as a list of key-value pairs with that team.name & item.id
Like this:
"item.team":{
"item.id":"item.name",
"item.id":"item.name",
"item.id":"item.name",
.....
}
If we can return a Map<String, List<Item>>, where the key is the team and the value is a List<Item> belonging to that team, we can use
final Map<String, List<Item>> itemsByTeam =
items.stream().collect(Collectors.groupingBy(item -> item.team));
Ideone demo
Remark: This solution was first posted in a comment by another user and they deleted the comment shortly after. I do not remember the user's name. If they post an answer, I will delete mine. If they do not want to post an answer, but contact me, I will credit them by name.
A comment on the code: I would recommend to introduce getters for the attributes since the stream-operation is most likely to be called outside of class Item itself, hence attribute team will not be visible. Also, this would lead to an implementation like
final Map<String, List<Item>> itemsByTeam =
items.stream().collect(Collectors.groupingBy(Item::getTeam));
which may or may not be regarded as "more pleasing" to the reader.
From the accepted answer by Turing85.
I have created a complete solution for the Question I asked.
To create an output with the following structure:
"item.team":{
"item.id":"item.name",
"item.id":"item.name",
"item.id":"item.name",
.....
}
Source data:
List<Item> itemsListData = //Get the data
Function to group the Items:
public static Map<String, List<Item>> groupItemsByTeam(Collection<Item> itemsList) {
return itemsList.stream().collect(Collectors.groupingBy(Item::team));
}
Structure the items list returned by groupItemsByTeam:
//GET THE GROUPED DATA
Map<String, List<Item>> result = groupItemsByTeam(itemsListData);
//STRUCTURE THE GROUPED DATA
for (Entry<String, List<Item>> parentItem : result .entrySet()) {
System.out.println(parentItem .getKey() + " : "); // item.team value
for (Item childItem : parentItem.getValue()) {
System.out.println(childItem.getKEY() + " = " + childItem.getVALUE());
}
System.out.println("-------------------------------------------");
}
OUTPUT:
Team A :
Item 1= Item 1 name
Item 2= Item 2 name
-------------------------------------------
Team G :
Item 456= Item 456 name
Item 254= Item 254 name
-------------------------------------------
Reference from baeldung.com
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);
}
}
I have got two ArrayLists, created from parsed html. First one contains jobs and is like
Job A
Job B
Job C
and the second one is like
Company A
Company B
Company C
What I need is combination of Job A and Company A and so on, so I can get the results like (an ArrayList too would be great)
Job A : Company A
Job B : Company B
Job C : Company C
I didn't find clear tutorial or something. Any ideas?
Are you sure you are looking at the correct data structure to achieve this?
Why not use a Map? You can define a key/value relationship going this route.
Map<Company, Job> jobMap = new HashMap<Company, Job>();
jobMap.put("Company A" /* or corresponding list item */, "Job A" /* or corresponding list item */);
You may even do something like this: (Swap out the strings to your to fit your implementation)
Map<Company, List<Job>> jobMap...;
List<Job> jobList = new ArrayList<Job>();
jobList.add("Job A");
jobList.add("Job B");
jobList.add("Job C");
jobMap.put("Company A", jobList);
What this will do is define a company as your key and you can set multiple jobs to a company
if (jobs.length() != companies.length()) {
throw new InvalidArgumentException("Mismatch of jobs and companies");
}
for (int i = 0; i < jobs.length(); i++) {
combine(jobs.get(i), companies.get(i));
}
There are lots of ways to combine references between two kinds of objects. Here's a flexible example that will let you use one to look up the other. It's overkill if you know which you'd always be using to do the lookup. Using LinkedHashMap also preserves the insertion order. So if you decide to put them in B, C, A order, you can get them out in B, C, A order.
LinkedHashMap<Job, Company> jobToCompany = new LinkedHashMap<>();
LinkedHashMap<Company, Job> companyToJob = new LinkedHashMap<>();
private void combine(Job job, Company company) {
jobToCompany.put(job, company);
companyToJob.put(company, job);
}
If you really want to store the combined values in an ArrayList then the following code will work for you:
List<String> jobs = new ArrayList<>();
List<String> companies = new ArrayList<>();
List<String> mergedList = new ArrayList<>();
//assuming the value are populated for `jobs` and `companies`.
if(jobs.size() == companies.size()) {
int n = jobs.size();
for(int index=0; index<n; index++)
{
mergedList.add(jobs.get(index) + " : " + companies.get(index))
}
} else {
System.out.println("Cannot combine");
//Throw exception or take any action you need.
}
Keep in mind that if you need to search for any item it would be O(n) but I assume you are aware of it before taking decision of going with an ArrayList.
If you're not willing to use a Map (not sure why you would that) my approach would be: To create another class (lets call it CompanyJob) that would contain both a Company and a Job attribute, then simply have a collection of your CompanyJob instances (an ArrayList would do).
class CompanyList{
private Company mCompany;
private Job mJob;
public CompanyList (Company com, Job job){
mCompany = com;
mJob = job;
}
// Some logic ...
}
// Then your list
private ArrayList<CompanyList> yourList = new ArraList <>();
int i = 0;
for (Company tmpCom: companyList){
yourList.add (new CompanyJob (tmpCom,jobList.get(i));
i++;
}
You need to create a new one
List<String> third = new ArrayList<String>();
Also need a counter.
int position = 0;
Then iterate through the list (considering the size is same for both the list).
for(String item:firstList){
third.add(item+ " : " + secondList.get(position);
position ++;
}
Then the third will have the desired result.
To confirm:
for (String item:third){
//try to print "item" here
}
I have an Arraylist of Records.
package com.demo.myproject;
public class Records
{
String countryName;
long numberOfDays;
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public long getNumberOfDays() {
return numberOfDays;
}
public void setNumberOfDays(long numberOfDays) {
this.numberOfDays = numberOfDays;
}
Records(long days,String cName)
{
numberOfDays=days;
countryName=cName;
}
}
My Arraylist<Records> is containing the values
Singapore 12
Canada 3
United Sates 12
Singapore 21
I need to modify it such that my output is
Canada 3
Singapore 33
United States 12
Please help me with solution,approach.
You could store your Records in a Map, where the key would be the country.
When you receive a new Record, check if the country already is in the map, if it is, add the number of days, if not create it.
Map<String, Record> map = new HashMap<String, Record> ();
addRecord(map, someRecord);
private void addRecord(Map<String, Record> map, Record record) {
Record inMap = map.get(record.getCountryName());
if (inMap == null) {
inMap = record;
} else {
inMap.setNumberOfDays(inMap.getNumberOfDays() + record.getNumberOfDays());
}
map.put(record.getCountryName(), inMap);
}
Notes:
I have assumed that it is fine to modify the records - if not just create a new one using the sum of the days.
you can still get the collection of records by calling map.values(); and iterate over them
ArrayList is not very well suited for your use case. If you really need to stick to ArrayList, for evey new record, you would need to loop over the list, check if one of the records in the list has the same country as the new record, update that record if you find it, or add a new record if not.
public class RecordsMain {
static ArrayList<Records> al = new ArrayList<Records>();
static boolean flag = false;
public static void main(String[] args) {
Records rec1 = new Records(12,"Singapore");
Records rec2 = new Records(3,"Canada");
Records rec3 = new Records(12,"United States");
Records rec4 = new Records(21,"Singapore");
addToList(rec1);
addToList(rec2);
addToList(rec3);
addToList(rec4);
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i).getCountryName() + " :: " + al.get(i).getNumberOfDays());
}
}
public static void addToList(Records records) {
for (int i = 0; i < al.size(); i++) {
if(al.get(i).getCountryName().equals(records.getCountryName())) {
al.get(i).setNumberOfDays(al.get(i).getNumberOfDays()+records.getNumberOfDays());
flag=true;
}
}
if (flag == false)
al.add(records);
}
}
Note:
The function addToList adds records and while adding itself checks whether the CountryNames are duplicate, if they are it adds the No of days and does not marks any new entry to the ArrayList.
I was not sure if you were looking for sorting of the List too, thus did not try that.
I suppose you create these records on your own. If you don't need any specific order of the elements you should use the HashMap and as assylias said - create country elements only when they doesn't exist. When you need to keep the order of elements (or sort them later by name etc) you can still use the ArrayList and "indexOf()" method to easily find them.
I dont know what exactly you want to do there but if you want to sort it with specific criteria then You could use comparable or comparator interfaces to sort your records using your criteria in ArrayList And use collections.sort() method to sort it.