What I am doing is getting elements from a map and adding them onto a JList to display on a GUI. I want to know how to sort the names alphabetically.
private void refreshShopsList() {
gameShopsJList.setModel(new javax.swing.AbstractListModel<String>() {
public int getSize() {
return ShopsLoader.getShops().size();
}
public String getElementAt(int i) {
return getShopByIndex(i).getName();
}
});
}
private Shop getShopByIndex(int index) {
Iterator<Entry<String, Shop>> it = ShopsLoader.getShops().entrySet().iterator();
int count = -1;
while(it.hasNext()) {
Entry<String, Shop> entry = it.next();
count++;
if (count == index)
return entry.getValue();
}
return null;
}
/**
* The map of the shops
*/
private static final Map<String, Shop> shops = new HashMap<String, Shop>();
public static Map<String, Shop> getShops() {
return shops;
}
Here is a little example, which sorts your shop names.
The ShopComparator class does the sorting task:
package model;
import java.util.Comparator;
public class ShopComparator implements Comparator<Shop> {
#Override
public int compare(Shop o1, Shop o2) {
return o1.getName().compareTo(o2.getName());
}
}
The Shop class, as simple as possible:
package model;
public class Shop {
private int id;
private String name;
public Shop(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And the main app:
package model;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
public class App {
public static void main(String[] args) {
Map<String, Shop> shops = new HashMap<String, Shop>();
Shop s1 = new Shop(1, "Apus Drugstore");
Shop s2 = new Shop(2, "DM");
Shop s3 = new Shop(3, "Kaufhof");
Shop s4 = new Shop(4, "Moes Traverne");
shops.put("one", s3);
shops.put("two", s4);
shops.put("three", s1);
shops.put("four", s2);
for(Shop s : shops.values()) {
System.out.println(s.getName());
}
ShopComparator sc = new ShopComparator();
TreeSet<Shop> sortedShops = new TreeSet<>(sc);
sortedShops.addAll(shops.values());
for(Shop s : sortedShops) {
System.out.println(s.getName());
}
}
}
First output, unsorted:
Moes Traverne
Kaufhof
Apus Drugstore
DM
and the sorted output.
Apus Drugstore
DM
Kaufhof
Moes Traverne
Algorithm:
get all values from JList, convert them to strings, store in array
sort the array
set new values to JList.
code:
JList jl = new JList(new Object[]{4.5,1,"Hi!"});
ListModel model = jl.getModel();
String[] strings = new String[model.getSize()];
for(int i=0;i<strings.length;i++){
strings[i]=model.getElementAt(i).toString();
}
Arrays.sort(strings);
jl.setListData(strings);
see about Comparator if you need to sort array in any other order.
Related
I am trying to query a property of all items in a map.
I can do it with a collection, but it does not work for map.
I have tries many variation, but did not find a way to get all ids of objects in map.
See complete code example below.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.jxpath.JXPathContext;
public class TestMap {
public static void main(String[] args) {
Person p = createPerson(1);
p.foes = new HashMap<>();
p.foes.put("a", createPerson(2));
p.foes.put("b", createPerson(3));
p.friends = new ArrayList<>();
p.friends.add(createPerson(4));
p.friends.add(createPerson(5));
//works
Iterator<Object> friendsId = JXPathContext.newContext(p).iterate("friends/id");
friendsId.forEachRemaining(o -> System.out.println(o));
// works
Iterator<Object> foesId = JXPathContext.newContext(p).iterate("foes/a/id");
foesId.forEachRemaining(o -> System.out.println(o));
// does not works :(
foesId = JXPathContext.newContext(p).iterate("foes/id");
foesId.forEachRemaining(o -> System.out.println(o));
}
private static Person createPerson(Integer id) {
Person p = new Person();
p.setId(id);
return p;
}
public static class Person {
private Integer id;
private List<Person> friends;
private Map<String, Person> foes;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Person> getFriends() {
return friends;
}
public void setFriends(List<Person> friends) {
this.friends = friends;
}
public Map<String, Person> getFoes() {
return foes;
}
public void setFoes(Map<String, Person> foes) {
this.foes = foes;
}
}
}
https://commons.apache.org/proper/commons-jxpath/users-guide.html#Map_Element_Access
found it : "foes/*/id" works.
A bit obvious
We have a ArrayList. It contains duplicate employee objects with only difference in their age, but name and id will be same. So while removing the duplicates, we have to keep the employee with maximum age and remove all other duplicates. This is one of the questions asked by an interviewer in one of the interviews.
I tried solving this. It is giving me correct result, but I am not sure with my approach as I am changing the state of the object in equals method. Is there any other approach to solve this problem?
Code Snippet below: -
package practice;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class Employee {
private int id;
private String name;
private int age;
Employee(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public int hashCode() {
return (31*(name.hashCode()) + 31);
}
#Override
public boolean equals(Object obj) {
if ((obj instanceof Employee)) {
if (((Employee)obj).getId() == this.id && (((Employee)obj).getName().equalsIgnoreCase(this.name))) {
if(this.age > ((Employee)obj).getAge()) {
((Employee)obj).setAge(this.age);
}
return true;
} else
return false;
} else
return false;
}
}
public class ListDuplicateRemoval {
public static List<Employee> removeDuplicates(List<Employee> employees) {
Set<Employee> set = new HashSet<>();
for (int i = 0; i < employees.size(); i++) {
set.add(employees.get(i));
}
/*for (int i = 0; i < set.size(); i++) {
System.out.println(set.iterator().next().getAge());
}*/
employees.removeAll(employees);
employees.addAll(set);
return employees;
}
public static void main(String[] args) {
Employee e1 = new Employee(1, "Mike", 20);
Employee e2 = new Employee(1, "Mike", 21);
List <Employee> list = new ArrayList<>();
list.add(e1);
list.add(e2);
removeDuplicates(list);
System.out.println(list.size());
System.out.println(list.get(0).getAge());
}
}
No this solution is really awful. equals should never, ever, modify the state of the objects it's comparing.
Create a class containing the information that identifies employees uniquely, and which properly override equal() and hashCode(). Then use a Map containing these identication info as key, and the employee with the largest age as value. Then get the values and make it a list:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
class Employee {
private int id;
private String name;
private int age;
Employee(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
int getId() {
return id;
}
String getName() {
return name;
}
int getAge() {
return age;
}
#Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
class DuplicateRemoval {
public static void main(String[] args) {
List<Employee> employeeList = Arrays.asList(
new Employee(1, "Joe", 23),
new Employee(2, "Joe", 23),
new Employee(1, "Joe", 21),
new Employee(1, "Jane", 22),
new Employee(1, "Jane", 20)
);
Map<EmployeeKey, Employee> map = employeeList.stream().collect(
Collectors.toMap(e -> new EmployeeKey(e.getId(), e.getName()),
Function.identity(),
(e1, e2) -> e1.getAge() > e2.getAge() ? e1 : e2)
);
List<Employee> result = new ArrayList<>(map.values());
System.out.println("result = " + result);
}
private static class EmployeeKey {
private int id;
private String name;
EmployeeKey(int id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
EmployeeKey that = (EmployeeKey) o;
return id == that.id &&
Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(id, name);
}
}
}
Implement a Comparator<Employee>
Have the compare method take into account age.
Have the equals method ignore age.
use equals to identify duplicates.
use compare to determine which duplicate to keep.
Can we make the class immutable which has collection as one of the fields?
public class Student implements Comparable<Student> {
private int rollNumber;
private String name;
private Set<String> subjects;
private List<Integer> marks ;
public Student(int rollNumber, String name, Set<String> subjects,
List<Integer> marks) {
this.rollNumber = rollNumber;
this.name = name;
this.subjects = Collections.unmodifiableSet(subjects);
this.marks = Collections.unmodifiableList(marks);
setPercentage();
}
private float percentage;
public int getRollNumber() {
return rollNumber;
}
public String getName() {
return name;
}
public Set<String> getSubjects() {
return new HashSet<>(subjects);
}
public List<Integer> getMarks() {
return new ArrayList<>(marks);
}
public float getPercentage() {
return percentage;
}
private void setPercentage() {
float sum = 0;
for (Integer i : marks)
sum = sum + i;
if (!marks.isEmpty())
percentage = sum / marks.size();
}
}
I am not able to achieve it.
I tried:
Set<String> subjects= new HashSet<>();
subjects.add("Maths");
subjects.add("Science");
subjects.add("English");
List<Integer> marks1= new LinkedList<Integer>();
marks1.add(45);
marks1.add(36);
marks1.add(98);
Student student1= new Student(1, "Payal", subjects, marks1);
//student1.getSubjects().add("History");
subjects.add("History");
System.out.println(student1);
But subjects.add is changing the state of the object.
Please help.
You're making a copy of both collections before returning them from your getters. This is unnecessary, since the collections are unmodifiable (unless you want the caller to get mutable collections and not unmodifiable ones).
What is necessary is to make copies of the collections that are passed from the outside in the contructor. Otherwise, the caller can still modify the collections after they've been stored in your object:
this.subjects = Collections.unmodifiableSet(new HashSet<>(subjects));
this.marks = Collections.unmodifiableList(new ArrayList<>(marks));
To be truly immutable, the class and its fields should also be final.
public class Student implements Comparable<Student> {
private int rollNumber;
private String name;
private Set<String> subjects;
private List<Integer> marks ;
public Student(int rollNumber, String name, Set<String> subjects,
List<Integer> marks) {
this.rollNumber = rollNumber;
this.name = name;
this.subjects = new HashSet<>(subjects);
this.marks = new ArrayList<>(marks);
setPercentage();
}
private float percentage;
public int getRollNumber() {
return rollNumber;
}
public String getName() {
return name;
}
public Set<String> getSubjects() {
return new HashSet<>(subjects);
}
public List<Integer> getMarks() {
return new ArrayList<>(marks);
}
public float getPercentage() {
return percentage;
}
private void setPercentage() {
float sum = 0;
for (Integer i : marks)
sum = sum + i;
if (!marks.isEmpty())
percentage = sum / marks.size();
}
}
I did this. It worked. If I try these 2 operations now, no problem.
Set<String> subjects= new HashSet<>();
subjects.add("Maths");
subjects.add("Science");
subjects.add("English");
List<Integer> marks1= new LinkedList<Integer>();
marks1.add(45);
marks1.add(36);
marks1.add(98);
Student student1= new Student(1, "Payal", subjects, marks1);
student1.getSubjects().add("History");
subjects.add("History");
System.out.println(student1);
Here is the answer
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Student implements Comparable<Student> {
private final int rollNumber;
private final String name;
private final Set<String> subjects;
private final List<Integer> marks;
public Student(int rollNumber, String name, Set<String> subjects, List<Integer> marks) {
this.rollNumber = rollNumber;
this.name = name;
this.subjects = new HashSet<>(subjects);
this.marks = new ArrayList<>(marks);
setPercentage();
}
private float percentage;
public int getRollNumber() {
return rollNumber;
}
public String getName() {
return name;
}
public Set<String> getSubjects() {
return Collections.unmodifiableSet(subjects);
}
public List<Integer> getMarks() {
return new ArrayList<>(marks);
}
public float getPercentage() {
return percentage;
}
private void setPercentage() {
float sum = 0;
for (Integer i : marks) {
sum = sum + i;
}
if (!marks.isEmpty()) {
percentage = sum / marks.size();
}
}
#Override
public String toString() {
return subjects.toString();
}
#Override
public int compareTo(Student o) {
return -1;
}
}
Main Method :
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class NewClass {
public static void main(String[] args) {
Set<String> sub = new HashSet<>();
sub.add("Maths");
sub.add("Science");
sub.add("English");
List<Integer> marks1 = new LinkedList<Integer>();
marks1.add(45);
marks1.add(36);
marks1.add(98);
Student student1 = new Student(1, "Payal", sub, marks1);
sub.add("History");
System.out.println(student1);
}
}
1 : Reason why other code is not working is they make collection unmodifiableSet and unmodifiableList but to the local object while we just need to create new object instead of pointing old reference.
2 : And Second prevent modification of return value, for that just make instance variable to final or you can create new collection object and return it, but if you do that then it create new object each time you call getXXXX method while actually you don't need that object.
Is it possible to store three string values added into an array (studentName), and store that into a different array so it can be found later?
Basically my main goal is to store a name, user id, and a balance (fullName, idName, 300).
And add that into a "super(?)" array so when people type down, it finds the fullName and pulls the information from there.
You can create a class
public class Student {
private String name;
private String id;
private int balance;
}
and then you can create a list of these objects:
List<Student> list = new ArrayList<Student>();
Map<String, String> map = new HashMap<String, String>();
then:
List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
and then:
map.put("name", "Thomas");
map.put("id", "Thomas id");
map.put("balance", ""300);
listOfMaps.add(map);
Anyhow, be careful. You will have to keep numbers (f.e. balance) as a String and after you will need to map it.
Well, I believe you are talking about something like Jagged Array which is available in C# but for java, we can do it in some other ways... like creating a class and manipulating it as Generic List implementation...
public class Student {
private String name;
private int id;
private int balanace;
public Student(){}
public Student(String name, int id, int balance){
this.name = name;
this.id = id;
this.balanace = balance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalanace() {
return balanace;
}
public void setBalanace(int balanace) {
this.balanace = balanace;
}
}
In some other class where you would want to manipulate
public class ManipulateData {
public static void main(String[] args){
Student student1 = new Student("James", 1, 500);
List<Student> list = new ArrayList<Student>();
list.add(student1);
for(Student s: list){
System.out.println("Name : " + s.getName());
System.out.println("ID : " + s.getId());
System.out.println("Balance : " + s.getBalanace());
}
}
}
I have a map that looks like this: HashMap<Person, List<Items>>.
I want to remove a few of the items in the list, the specific items i want to remove are stored in another list. How could i remove the list-items in the map that match with the items in this other list in the most efficient way?
Here is a full example demonstrating your situation. Notice that hashcode and equals were implemented on the Item class. This is important because it equals will be used by the removeAll method to determine if the list of supplied items is equal to the list of possessed items.
Item.java
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Item(String name) {
super();
this.name = name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Item other = (Item) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
Person.java
public class Person {
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Application
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class StackTest {
public static void main(String[] args) {
Person person = new Person("Logan");
Person person2 = new Person("Jean");
Person person3 = new Person("Gambit");
Person person4 = new Person("Storm");
Item item1 = new Item("Claws");
Item item2 = new Item("Jacket");
Item item3 = new Item("Cards");
Item item4 = new Item("Cape");
List<Item> items = new ArrayList<Item>();
items.add(item1);
items.add(item2);
items.add(item3);
items.add(item4);
List<Item> loganItems = new ArrayList<Item>(items);
List<Item> jeanItems = new ArrayList<Item>(items);
List<Item> gambitItems = new ArrayList<Item>(items);
List<Item> stormItems = new ArrayList<Item>(items);
Map<Person, List<Item>> people = new HashMap<Person,List<Item>>();
people.put(person, loganItems);
people.put(person2, jeanItems);
people.put(person3, gambitItems);
people.put(person4, stormItems);
printMap(people);
List<Item> removeItems = new ArrayList<Item>();
Item rItem1 = new Item("Cards");
Item rItem2 = new Item("Jacket");
removeItems.add(rItem1);
removeItems.add(rItem2);
removeItem(people, person, removeItems);
printMap(people);
}
public static void removeItem(Map<Person,List<Item>> map, Person p, List<Item> items){
map.get(p).removeAll(items);
}
public static void printMap(Map<Person, List<Item>> map){
for(Entry<Person,List<Item>> entry:map.entrySet()){
System.out.println(entry.getKey().getName() + " items:");
for(Item item: entry.getValue()){
System.out.println(item.getName());
}
}
}
}
List already provides a method: List.removeAll(Collection<?> collection).
Of course, using a LinkedList would probably be preferable in this scenario as removing an element is a O(1) operation vs O(n) for an ArrayList.
HashMap<Person, List<Items>> map = // Your map
for(Person p:map.keySet()) {
map.get(p).removeAll(removeList);
}
This should work.