I have a list of an Object and I want to detect whether Object Id is duplicate or not.
Here is the object:
public class data{
private String id;
private String value;
private String status;
}
All duplicate data will have "invalid" status except the first one.
What is the most effective way for this?
You could consider overriding the .equals() method of the data class.
Doing so would allow you to do the following to check for duplicate elements:
ArrayList<data> array_list = new ArrayList<data>();
// add some elements to array list
// check for duplicates
for(int i =0; i < array_list.size(); i++){
for(int j=0; j<array_list.size(); j++){
// compare for equality if it is not the same element
if(i != j){
if(array_list.get(i).equals(arrayList.get(j))){
// than we know there is a duplicate at index i,j
System.out.println("duplicate indexes: " + i + ", " + "j");
}
}
}
}
Here is an example of how you would override the .equals method of the data class.
#Override
public boolean equals(Object obj) {
if (!(obj instanceof data)){ return false; }
if (obj == this) { return true; }
// compare strings to see if they are equal
data other_data = (data)obj;
boolean id_equal = other_data.id.equals(this.id);
boolean value_equal = other_data.value.equals(this.value);
boolean status_equal = other_data.status.equals(this.status);
return id_equal && value_equal && status_equal
}
Edit
If you only want to know whether the id's are equal or not you don't need to override .equals() of the data class.
In this case you need only need to use the first loop and compare the id stings instead of the data objects.
So instead of array_list.get(i).equals(arrayList.get(j),
you would do (assuming you have getter methods for the private members of data):
array_list.get(i).get(id).equals(array_list.get(j).get(id));
Alternatively you could use a method similar to the first one and override .equals() to only compare the id strings.
use java ConcurrentHashMap instead of arraylist.
ConcurrentHashMap<yourid, YourBean> chp = new ConcurrentHashMap<>();
chp.putIfAbsent(yourid, YourBean);
and to list all your id do something like this
for (Entry<yourid, YourBean> e : chp.entrySet())
{
YourBean object = (YourBean )chp.get(e.getKey());
//do what u want with your object, guess that helps
}
Try like this first you should override equals method to check duplicates
private class data{
private String id;
private String value;
private String status;
public data(String id, String value, String status) {
this.id = id;
this.value = value;
this.status = status;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
return "data{" +
"id='" + id + '\'' +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof data)) return false;
data data = (data) o;
return !(id != null ? !id.equals(data.id) : data.id != null);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Then test like this
public class Test {
public static void main(String[] args ) {
List<data> dataList=new ArrayList<>();
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("2","somevalue","somestatus"));
dataList.add(new data("3","somevalue","somestatus"));
List<data>validList=new ArrayList<>();
List<data>duplicateList=new ArrayList<>();
for (data data:dataList){
if (!(validList.contains(data))){
validList.add(data);
System.out.println(validList);
}else{
duplicateList.add(data);
System.out.println(duplicateList);
}
}
}
Make a list of the id of objects. Loop over the list of objects. See if the id of each object is already in the list. If the id is already present, then change the status of the object. Otherwise, add the id of the object to the list.
Related
I want to sort an ArrayList in ascending order and in descending order by comparing a String value or an Enum value.
This is the ArrayList I want to sort :
List<Issue> issues;
The list will be sorted depending on two params (field and sort) I give to a function :
private List<Issue> sortList(List<Issue> list, String field, String sort) {
// My code goes here
}
So let's assume that the field value is title and the sort values is DESC then I want to order all Issue elements in the list by their title filed, this is what I tried :
return list.stream().sorted((i1, i2) -> String.compare(i2.getTitle(), i1.getTitle())).collect(Collectors.toList());
But this generates the following error :
The method compare(String, String) is undefined for the type String
For the enums I couldn't figure out how to compare their values.
How can I solve this ?
Classes definition :
Issue :
public class Issue {
private IssueElementEnum issueElement;
private IssueTypeEnum issueType;
private String title;
// Getters and setters
}
IssueElementEnum:
public enum IssueElementEnum {
PROFILE {
#Override
public String toString() {
return "Profil";
}
}
ROLE {
#Override
public String toString() {
return "Rôle";
}
},
User {
#Override
public String toString() {
return "Utilisateur";
}
}
}
IssueTypeEnum:
public enum IssueTypeEnum {
PROFILE {
#Override
public String toString() {
return "Sans Profil";
}
},
ROLE {
#Override
public String toString() {
return "Sans Rôle";
}
},
USER {
#Override
public String toString() {
return "Sans Utilisateur";
}
}
}
Edit :
Sometimes I want to sort my list with more than one field, for example (sort the list by title in ascending order and then by issueElement.toSting() in descending order, for that I created the following class :
public class SortDTO implements ISort {
public static final String ASC = "ASC";
public static final String DESC = "DESC";
private String field;
private String sort;
public GridSortDTO() {
this(null, null);
}
public GridSortDTO(final String field, final String sort) {
super();
this.field = field;
this.sort = sort;
}
#Override
public String getField() {
return field;
}
#Override
public void setField(final String field) {
this.field = field;
}
#Override
public String getSort() {
return sort;
}
#Override
public void setSort(final String type) {
this.sort = type;
}
#Override
public String toString() {
return String.format("Sort[field=%s, sort=%s]", this.field, this.sort);
}
}
public interface ISort {
String getField();
void setField(final String field);
String getSort();
void setSort(final String type);
}
Then my sort informations are stored in this array : GridSortDTO[] sorts.
So for example sorts will contain this information :
[{"field":"title","sort":"asc"},{"field":"issueElement","sort":"desc"}]
How can I implement this ?
It’s not clear which order you want for the enum types, declaration order (PROFILE, ROLE, USER) or lexicographic order of their toString() representation.
In the latter case, you could implement the method as
private List<Issue> sortList(List<Issue> list, String field, String sort) {
Function<Issue,String> f;
switch(field) {
case "Title": f = Issue::getTitle; break;
case "IssueElement": f = i -> i.getIssueElement().toString(); break;
case "IssueType": f = i -> i.getIssueType().toString(); break;
default: throw new IllegalArgumentException("unknown property '"+field+"'");
}
Comparator<Issue> cmp = Comparator.comparing(f);
if("DESC".equalsIgnoreCase(sort)) cmp = cmp.reversed();
else if(!"ASC".equalsIgnoreCase(sort))
throw new IllegalArgumentException("invalid sort '"+sort+"'");
return list.stream().sorted(cmp).collect(Collectors.toList());
}
If you want to use the enum declaration order instead, you have slightly less common code:
private List<Issue> sortList(List<Issue> list, String field, String sort) {
Comparator<Issue> cmp;
switch(field) {
case "Title": cmp = Comparator.comparing(Issue::getTitle); break;
case "IssueElement": cmp = Comparator.comparing(Issue::getIssueElement); break;
case "IssueType": cmp = Comparator.comparing(Issue::getIssueType); break;
default: throw new IllegalArgumentException("unknown property '"+field+"'");
}
if("DESC".equalsIgnoreCase(sort)) cmp = cmp.reversed();
else if(!"ASC".equalsIgnoreCase(sort))
throw new IllegalArgumentException("invalid sort '"+sort+"'");
return list.stream().sorted(cmp).collect(Collectors.toList());
}
Instead of the switch statement, you could also maintain a map of existing orders, which offers more flexibility:
// in Java 9, you should replace Arrays.asList(...) with List.of(...)
static final Map<List<String>,Comparator<Issue>> ORDER;
static {
Map<List<String>,Comparator<Issue>> m = new HashMap<>();
Comparator<Issue> c = Comparator.comparing(Issue::getTitle);
m.put(Arrays.asList("Title", "asc"), c);
m.put(Arrays.asList("Title", "desc"), c.reversed());
c = Comparator.comparing(Issue::getIssueElement);
m.put(Arrays.asList("IssueElement", "asc"), c);
m.put(Arrays.asList("IssueElement", "desc"), c.reversed());
c = Comparator.comparing(Issue::getIssueType);
m.put(Arrays.asList("IssueType", "asc"), c);
m.put(Arrays.asList("IssueType", "desc"), c.reversed());
ORDER = Collections.unmodifiableMap(m);
}
private List<Issue> sortList(List<Issue> list, String field, String sort) {
Comparator<Issue> cmp = ORDER.get(Arrays.asList(field, sort.toLowerCase(Locale.ROOT)));
if(cmp == null)
throw new IllegalArgumentException("property '"+field+"', sort '"+sort+"'");
return list.stream().sorted(cmp).collect(Collectors.toList());
}
This approach can be adapted to your new requirement, though, I strongly suggest a slight redesign:
enum Direction { ASCENDING, DESCENDING }
public interface ISort {
String getField();
void setField(final String field);
Direction getSort();
void setSort(final Direction type);
}
Adapting the implementation is straight-forward, but you should avoid allowing null for the sorting direction, as then, it’s intrisically only either of the two legal values:
public class SortDTO implements ISort {
private String field;
private Direction sort;
public SortDTO() { this(null, Direction.ASCENDING); }
public SortDTO(String field, Direction sort) {
this.field = field;
this.sort = sort;
}
public String getField() { return field; }
public void setField(String field) { this.field = field; }
public Direction getSort() { return sort; }
public void setSort(Direction sort) { this.sort = Objects.requireNonNull(sort); }
#Override
public String toString() {
return String.format("Sort[field=%s, sort=%s]", this.field, this.sort);
}
}
We augment these types with an immutable key type capable of capturing the current state of an ISort implementation and having proper equals and hashCode implementations:
final class SortKey {
final String field;
final Direction direction;
private SortKey(String f, Direction d) { field=f; direction=d; }
#Override
public int hashCode() {
return field.hashCode()*2+direction.ordinal();
}
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof SortKey)) return false;
SortKey that = (SortKey)obj;
return this.direction == that.direction && this.field.equals(that.field);
}
static SortKey of(String field, Direction dir) {
return new SortKey(Objects.requireNonNull(field), Objects.requireNonNull(dir));
}
static SortKey of(ISort s) {
return of(s.getField(), s.getSort());
}
}
Then, the adapted solution may look like
static final Map<SortKey,Comparator<Issue>> ORDER;
static {
Map<SortKey,Comparator<Issue>> m = new HashMap<>();
Comparator<Issue> c = Comparator.comparing(Issue::getTitle);
m.put(SortKey.of("Title", Direction.ASCENDING), c);
m.put(SortKey.of("Title", Direction.DESCENDING), c.reversed());
c = Comparator.comparing(Issue::getIssueElement);
m.put(SortKey.of("IssueElement", Direction.ASCENDING), c);
m.put(SortKey.of("IssueElement", Direction.DESCENDING), c.reversed());
c = Comparator.comparing(Issue::getIssueType);
m.put(SortKey.of("IssueType", Direction.ASCENDING), c);
m.put(SortKey.of("IssueElement", Direction.DESCENDING), c.reversed());
ORDER = Collections.unmodifiableMap(m);
}
private List<Issue> sortList(List<Issue> list, ISort... order) {
if(order.length == 0) return new ArrayList<>(list);
Comparator<Issue> cmp = ORDER.get(SortKey.of(order[0]));
if(cmp == null) throw new IllegalArgumentException(order[0].toString());
for(int ix = 1; ix < order.length; ix++) {
Comparator<Issue> next = ORDER.get(SortKey.of(order[ix]));
if(next == null) throw new IllegalArgumentException(order[ix].toString());
cmp = cmp.thenComparing(next);
}
return list.stream().sorted(cmp).collect(Collectors.toList());
}
This allows an arbitrary number of sort criteria, the first being the primary order, the second being the secondary order and so on.
Actually, the method to compare two strings that you are trying to use is compareTo and not compare, which is defined in the Comparable interface. Take a look in the javadoc: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html
If you want to sort your list by the title just use the following:
stream().sorted(Comparator.comparing(Issue::getTitle)).collect(Collectors.toList())
Please have a look at java-8 Comparator
I am new to node lists and I need to search check whether a PersonNode associated with the given ID is in the list
the is my PersonNode class
public class PersonNode
{
// instance variables
private int m_ID;
private String m_name;
private PersonNode m_link;
// constructor
public PersonNode(int ID, String name)
{
m_ID = ID;
m_name = name;
m_link = null;
}
// getters and setters
public void setID(int ID)
{
m_ID = ID;
}
public int getID()
{
return m_ID;
}
public String getName()
{
return m_name;
}
public void setName(String name)
{
m_name = name;
}
public void setLink(PersonNode link)
{
m_link = link;
}
public PersonNode getLink()
{
return m_link;
}
}
here is my method class, constructor and instance variable. The method I don't know how to do is the contains method.
I edited this Class and I am still having so much trouble with this any help would be greatly appreciated.
public class SortedPersonList
{ // instance variables
private PersonNode m_first;
private int m_numElements;
// constructor
// Do not make any changes to this method!
public SortedPersonList()
{
m_first = null;
m_numElements = 0;
}
// check whether the list is empty
// Do not make any changes to this method!
boolean isEmpty()
{
if (m_first == null)
return true;
else
return false;
}
// return the size of the list (# of Person nodes)
// Do not make any changes to this method!
public int size()
{
return m_numElements;
}
// check whether a PersonNode associated with the given ID is in the list
public boolean contains(int ID)
{This Method I need help with!!
}
// search for and return the PersonNode associated with the given ID
public PersonNode get(int ID)
{ PersonNode current=m_first;
while(current!=null)
{if (current.getID()==ID)
return current;
}
return null;
}
// add a new PersonNode to the list with the given ID and name
public boolean add(int ID, String name)
{ PersonNode newNode=new PersonNode(ID,name);
PersonNode previous=null;
if (m_first == null)
{ // add element to an empty list
m_first = newNode;
m_first.setLink(previous);
m_numElements++;}
else
{if (newNode.getID()<m_first.getID())
{previous=m_first;
m_first=newNode;
m_first.setLink(previous);
m_numElements++;
}
else
{ m_first.setLink(newNode);
newNode.setLink(previous);
m_numElements++;}}
return true; // replace this statement with your own return
}
// remove a PersonNode associated with the given ID from the list
public boolean remove(int ID)
{PersonNode remove = get(ID);
while(remove.getID()==ID)
{m_first=null;
m_first.setLink(remove.getLink());}
m_numElements --;
return true;}
public String toString()
{
String listContent = "";
PersonNode current = m_first;
while (current != null)
{
listContent += "[" + current.getID() + " | " + current.getName() + "] ";
current = current.getLink();
}
return listContent;
}
}
If it helps the goal is to fix the add, contains, remove and get methods to implement a sorted linked list.
Let's assume you have a List<PersonNode> lst. You want to check if a PersonNode with id = ID is in this list lst. You can do that rather easily by just iterating over the list:
public boolean contains(int ID) {
for (PersonNode node : lst) {
if (node.getID() == ID)
return true; // node found, we can finish iterating
}
return false; // no node with id = ID was found
}
Take note that as of this moment you don't have a list in your SortedPersonList class. You probably want to have one as an instance variable.
Alternatively, if you decide that what you wanted to implement is an equivalent of a LinkedList, then you can do the same iteration just without foreach and instead advance with node.getNext()...
I am trying to create a HashMap, that adds objects to a line, if they are not already present in this line. This is how I check it:
if (!waiting.containsKey(p)) {
waiting.put(current, p);
current++;
}
Where p is our object, which is stored with an Integer. However, when I run this code. It will store the same object several times under different integers, how can this be prevented?
thats because you call containsKey with the object and not the key:
parameter must be an Integer key
Integer lKey = 0;
if(!waiting.containsKey(lKey)){
waiting.put(current, p);
current++;
}
if your object has an identifier use this identifier for the map.
if(!waiting.containsKey(p.getId())){
waiting.put(p.getId(), p);
current++;
}
otherwise use containsValue():
if(!waiting.containsValue(p)){
waiting.put(current, p);
current++;
}
but then you have to overwrite the equals method.
If you want to use an object as a key, you can override the equals() and hashCode() methods to return and compare the id of the object.
Driver.java
import java.util.HashMap;
import java.util.Map;
public class Driver {
public static void main(String[] args) {
Map<MyObject, Integer> map = new HashMap<MyObject, Integer>();
map.put(new MyObject(1000L, "One"), 1);
map.put(new MyObject(1001L, "Two"), 2);
map.put(new MyObject(1002L, "Three"), 3);
Long id = 1001L;
System.out.println(contains(map, id)); // true
System.out.println(get(map, id)); // 2
}
public static <T, U> boolean contains(Map<T, U> map, T obj) {
return map.containsKey(obj);
}
public static boolean contains(Map<MyObject, Integer> map, Long id) {
return contains(map, new MyObject(id, ""));
}
public static <T, U> U get(Map<T, U> map, T obj) {
return map.get(obj);
}
public static Integer get(Map<MyObject, Integer> map, Long id) {
return get(map, new MyObject(id, ""));
}
}
MyObject.java
public class MyObject {
private Long id;
private String name;
protected Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
protected String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public MyObject(Long id, String name) {
this.id = id;
this.name = name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.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;
MyObject other = (MyObject) obj;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
#Override
public String toString() {
return "MyObject { id : " + id + ", name : " + name + "}";
}
}
I got two "lists" of objects, which i want to compare if elements are equal. If they are not equal, the loop should take the not equal object and put it into the other list. Very simple. My problem is: the equals method doesnt work as intended.
Here is the object Class with my custom equals method:
public class Profil {
private String vorname;
private String name;
private String adLoginBenutzer;
public Profil() {
}
public String getAdLoginBenutzer() {
return adLoginBenutzer;
}
public void setAdLoginBenutzer(String adLoginBenutzer) {
this.adLoginBenutzer = adLoginBenutzer;
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
this.vorname = vorname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
if (name == null || vorname == null) {
return "<keiner>";
}
return vorname + ", " + name + " " + adLoginBenutzer;
}
#Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
Profil other = (Profil)obj;
if(!this.getVorname().equals(other.getVorname()) || !this.getName().equals(other.getName()) || !this.getAdLoginBenutzer().equals(other.getAdLoginBenutzer()))
{
return false;
}
return true;
}
}
And here is the loop: (note: I basically want to merge the list into a comboboxmodel, if the profil-object is not equal than it should add it to the first position in the comboboxmodel)
public void putProfilesIntoCbx(HashSet<Profil> profile)
{
DefaultComboBoxModel<Profil> cbx = (DefaultComboBoxModel <Profil>)cbBearbeiter.getModel();
for(Profil p : profile)
{
for(int i = 0; i< cbx.getSize(); i++)
{
if(!p.equals(cbx.getElementAt(i)))
{
cbx.insertElementAt(p, 0);
}
}
}
cbBearbeiter.setModel(cbx);
}
I debugged the code and took breakpoints at the last if of the equals method. Although there are equal objects, the last if return false for no reason even if the objects are really equal. Even if i invert the equals if-statement it does not work.
As everyone is saying, there is a relationship between the equals() method and the hashcode() method.
If you #Override the equals() method, you need to #Override the hashcode() method as well
I posted about this application yesterday, but now I'm having a different problem. I'm currently working on this application for tracking track (tracking track?) day runs and displaying a leaderboard. This is for a class so I'm not looking for code necessarily, just some thoughts on how to go about it. Anyway, the application currently will take input information (from the bottom textfields), create a TreeSet of RaceEntrant objects (class shown below), and create a queue on the right which is emptied as the participants go through their runs. The problem is, I need the TreeSet to be sorted in the (grey) leaderboard area from smallest to largest runTime and update while the times are entered at the top. I'm kind of unsure how to have it sort the objects specifically by the runTime. Any help is appreciated.
RaceEntrant Class
class RaceEntrant
{
private String name,
car;
private double runTime;
public RaceEntrant(String name, String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(double time)
{
this.runTime = time;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
}
This is an example of the current operation - the RaceEntrant(s) are displayed in order of their runs, not sorted by anything. I apologize for the lengthy post.
Your class, RaceEntrant, should implements Comparable, and you can control order in the implemented method compareTo.
Your class could look like this:
class RaceEntrant implements Comparable<RaceEntrant>
{
private final String name,
car;
private double runTime;
public RaceEntrant(final String name, final String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(final double time)
{
this.runTime = time;
}
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
#Override
public boolean equals(final Object obj) {
if(this == obj) return true;
if (obj instanceof RaceEntrant){
return (((RaceEntrant) obj).getTime() == runTime) && ((RaceEntrant) obj).getName().equals(name) && ((RaceEntrant) obj).getCar().equals(car);
}
return false;
}
#Override
public int hashCode() {
return new Double(runTime).intValue();
}
#Override
public int compareTo(final RaceEntrant o) {
return new Double(o.runTime).compareTo(this.runTime)*-1;
}
}
In your RaceEntrant class:
class RaceEntrant implements Comparable<RaceEntrant>{
//..
public int compareTo(RaceEntrant re){
return getTime().compareTo(re.getTime());
}
#Override //optional for Sets
public boolean equals(Object o){
If(o != null && o instanceOf RaceEntrant){
RaceEntrant entrant = (RaceEntrant)o;
return getName().equals(entrant.getName() &&
getCar().equals(entrant.getCar()) &&
getTime() == entrant.getTime();
}
}
}
Then you can sort your List (probably ArrayList) by runTime.
You could also use a TreeSet (this should be sorted automatically) and define a equals method on runTime + name + car if that's a possible approach.
I guess the TreeSet is not the right data structure. A TreeSet is above all a Set -- which keys are considered unique based on comparison.
I think you can have identical run times?
Maybe just use an ArrayList and sort it using Collections.sort() with a custom Comparator.