How to remove duplicates from list<object> - java

I have a object in java called foo.
I can do foo.getDate(); and that will give me the date of one item.
But now I have a list<foo> and I want to get per item one date.
So if I loop through my list I will see this output:
3-1-2015
3-1-2015
5-1-2015
8-1-2015
8-1-2015
But I want to see:
3-1-2015
5-1-2015
8-1-2015
So I want that only the first item with a unique date will be added to the list.
How can I do this in Java?
Thanks in advance!

Probably the most easy way would be use a map (HashMap for example)... Use the Date as a key, then put all your Foo objects into it. Then every time a key already exists the value will be overwritten and you'll end up with only one Foo object per Date. If you need a list (for sorting, for example) you can do something like new ArrayList<Foo>( myMap.values() ); then.

Create Set which will store unique Dates. If date from your foo instance was not already added to set add this instance to list containing foo objects with unique dates.
List<Foo> list = new ArrayList<>();
//fill list with your foo instances
Set<Date> uniqueDates = new HashSet<>();
List<Foo> resultList = new ArrayList<>();
for (Foo f : list){
if (uniqueDates.add(f.getDate())){//if I was able to add date to set
//it means that instance with this date is seen first time
//so I can add it to result list
resultList.add(f);
}
}

well you probably should use Set for this.

Just to add to #Pshemo's answer, doing the same with Java 8 is straightforward:
public class RemoveDuplicates {
public static void main(String[] args) {
// Initialize some dates
long now = System.currentTimeMillis();
Date d1 = new Date(now);
Date d2 = new Date(now - 10_000_000_000L);
Date d3 = new Date(now - 100_000_000_000L);
// Initialize some Foos with the dates
List<Foo> list = new ArrayList<>(Arrays.asList(
new Foo(d3), new Foo(d3), new Foo(d2),
new Foo(d1), new Foo(d1)));
Set<Date> uniqueDates = new HashSet<>();
// Filter foos whose date is already in the set
List<Foo> distinct = list.stream().filter(
f -> uniqueDates.add(f.getDate())).
collect(Collectors.toList());
System.out.println(distinct); // [Foo [date=17/01/12],
// Foo [date=24/11/14],
// Foo [date=19/03/15]]
}
static class Foo {
private static DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT);
private final Date date;
Date getDate() {
return this.date;
}
Foo(Date date) {
this.date = date;
}
#Override
public String toString() {
return "Foo [date=" + formatter.format(this.date) + "]";
}
}
}
The principle is exactly the same: if the date is already in the set, then the Foo is filtered from the stream.

Related

How to copy a List of key value except 1 key in Java?

I have 1 List of key:value pair primaryList in Java, now i want to copy complete list except one key date in primaryListExceptDate. Can anyone help me on this? I know we can do it using for loop but i want to know is there any other efficient way of doing it?
So as I understand you, you have a list of Record objects that keep pairs of values as key, value!?
Then you can use Stream api to do what you want. Something like:
List<Record> primaryListExceptDate = primaryList.stream()
.filter(record -> !record.getKey().equals(unwantedDateInstance))
.collect(Collectors.toList());
That will give you a new list without the Record with that unwanted date.
UPDATE: You asked for a Vector example.
I made this test which works fine, d2 is removed. Vector implements List so it can be cast. Collectors doesn't have a toVector method since Vector is outdated:
public class Testa {
public static void main(String[] args) {
Date d1 = new Date(100,1,2);
Date d2 = new Date(101,2,3);
Date d3 = new Date(102,3,4);
Date test = new Date(101,2,3);
Vector<Record> primaryList = new Vector<>();
primaryList.add(new Record(d1, new Object()));
primaryList.add(new Record(d2, new Object()));
primaryList.add(new Record(d3, new Object()));
List<Record> primaryListExceptDate = primaryList.stream()
.filter(record -> !record.getKey().equals(test))
.collect(Collectors.toList());
primaryListExceptDate.forEach(r -> System.out.println(r.getKey().toString()));
}
static class Record {
Date key;
Object value;
public Record(Date k, Object v) {
this.key = k;
this.value = v;
}
public Date getKey() {
return key;
}
}
}
Try a foreach construct to copy data into another List with an if to exclude the object that not interest to you. You may think it's not such an efficient way, but most of the methods the API offer have O(n) complexity.
I think it's the simplest method. You also could use List proper methods to copy the List and then remove the object, but this could be a bit more onerous if you look at performance.
Anyway, I suggest you to use Map Collection: it comes to rescue of you when using a key:value pair and it's very efficient! List is useless in this case.
I don't know if it's more efficient but you could first make a copy of the list and then iterate over it with an iterator and remove the entry with key 'date'.
EDIT: something like this:
List<Record> primaryList = ...;
List<Record> primaryListExceptDate = new ArrayList<>(primaryList );
Iterator<Record> it = primaryListExceptDate.iterator();
while(it.hasNext()) {
Record record = it.next();
if (record.getKey().equals("date")) {
it.remove();
}
}

Could some please explain Date maxDate = list.stream().map(u -> u.date).max(Date::compareTo).get();

Could some one please explain this:
Date maxDate = list.stream().map(u -> u.date).max(Date::compareTo).get();
Date maxDate =
list.stream() // create a Stream<TheElementTypeOfTheList>
.map(u -> u.date) // map each element of a Date, thus creating a Stream<Date>
.max(Date::compareTo) // find the max Date of the Stream
.get(); // return that max Date (will throw an exception if the
// list is empty)
The easiest to understand would be to decompose that into smaller pieces. Imagine a class that holds a Date object:
static class Holder {
public Date date;
public Holder(Date d) {
super();
}
}
List<Holder> list= Arrays.asList(new Holder(new Date()));
// creates a Stream<Holder> having the list as the source
Stream<Holder> s1 = list.stream();
// creates a Stream<Date> by taking the previous elements from the Stream
// and mapping those to `Date date`
Stream<Date> s2 = s1.map(u -> u.date);
// consumes the stream by invoking max using the compareTo method
// two Date objects are Comparable by invoking compareTo
Optional<Date> optionalDate = s2.max(Date::compareTo);
// gets the maxValue from that Optional
// if the initial list is empty, your last get will throw a NoSuchElementException
Date maxDate = optionalDate.get();

Stream query with two lists

I have a list of Visit objects, now I want to build another list containing available hours for given day;
public class Visit {
private int id;
private Date date;
private Time time;
private Pet pet;
private Vet vet;
this is the array String[] containing all visit hours:
public class VisitTime {
private static final String[] visitTime =
{"09:00:00","09:30:00","10:00:00","10:30:00","11:00:00","11:30:00","12:00:00",
"12:30:00","13:00:00","13:30:00","14:00:00","14:30:00","15:00:00","15:30:00","16:00:00","16:30:00"};
so now Im getting from Db list of visits (each visit has defined time), and checking if there is any other free time to schedule a visit.
I have written two methods to do so, one with iteration second with streams, both working as expected.
What I'm asking is how can I rebuild this method to NOT use terminal method twice.
public List<String> getHoursAvailable12(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId, date);
List<String> hoursAvailable = new ArrayList<>(Arrays.asList(VisitTime.getVisittime()));
List<String> hoursTaken = visitList.stream().map(Visit::getTime).map(Time::toString).collect(Collectors.toList());
return hoursAvailable.stream().filter(x -> !hoursTaken.contains(x)).collect(Collectors.toList());
}
and here is old-school method with collections:
public List<String> getHoursAvailable(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId,date);
ArrayList<String> hoursAvailable = new ArrayList<>(Arrays.asList(VisitTime.getVisittime()));
for(Visit x : visitList){
{
String time = x.getTime().toString();
if(hoursAvailable.contains(time)) hoursAvailable.remove(time);
}
}
return hoursAvailable;
}
You can try this. You get some benefit here, contains is faster in HashSet compared to List
public Set<String> getHoursAvailable(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId,date);
Set<String> hoursAvailable = new LinkedHashSet<>(
Arrays.asList(VisitTime.getVisittime()));
visitList.stream()
.map(Visit::getTime)
.map(Time::toString)
.forEach(vt-> hoursAvailable.removeIf(s->s.equals(vt)));
return hoursAvailable;
}

sort an ArrayList<String> according to dates parsed from the String

i have an Array List (of Type String) which looks like :
[2015-03-2, 2015-12-2, 2017-02-1, 2015-10-7, 2018-04-1, 2016-01-2, 2015-08-1, 2016-04-2, 2016-05-1, 2016-02-12, 2016-03-6]
i want to Sort it in descending order , e.g :
[2018-04-1, 2017-02-1,2016-05-1,2016-03-6,2015-03-2......]
i don't know how to do that since its not of Date type (items are String) i can't use Collections.sort(myArray) any idea or hint on how am gonna do this ? it'll be so helpful for me , thanks
UPDATE: i got to know what i need is something like :
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd h:m");
System.out.println(sdf.parse(startDate).before(sdf.parse(endDate)));
but i don't know where to start
Hope this works out:
Collections.sort(myArray,new Comparator<String>(){
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
#Override
public int compare(String s1, String s2){
return sdf.parse(s1).compareTo(sdf.parse(s2));
}
});
The above code uses the Collections API where Collections.sort is a method that is implemented by Java. There are 2 sort methods in the Collections class. first is to sort a list of Comparable elements. and the other will sort any List based on a Comparator which allows the user to write a specific logic for comparing 2 elements of a specific Type. Thus, all we need to implement is the Comparator to get our job done.
You can use sort function with:
Collections.sort(myArray, new Comparator<String>(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public int compare(String a, String b){
//Parse it into date and compare thr long values
return sdf.parse(a).compareTo(sdf.parse(b))
}
});
public class Main {
public static void main(String[] args) {
String[] list = new String[] {"2015-03-2", "2015-12-2", "2017-02-1", "2015-10-7", "2018-04-1", "2016-01-2", "2015-08-1", "2016-04-2", "2016-05-1", "2016-02-12", "2016-03-6"};
Arrays.asList(list).stream().map(s -> LocalDate.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-d"))).sorted().forEach(System.out::println);
}
}
Result
2015-03-02
2015-08-01
2015-10-07
2015-12-02
2016-01-02
2016-02-12
2016-03-06
2016-04-02
2016-05-01
2017-02-01
2018-04-01

Multi arraylist, trying to store timestamp with data

We have the code below which is a simple loop iterating through an arraylist and storing each iterated value into another arraylist. Each time an iteration is achieved, a timestamp value is obtained. How do we create or change the existing arrylist to store both a value and a timestamp together. Can we create a multi dimentional arraylist to do this ie arraylist [0],[0]. if so how?
int counter = 0; //current number of iterations
ArrayList<String> logData = new ArrayList<String>();
while (counter < TemData.size()) {
Thread.sleep(5000); // Sleep for 5000 milliseconds (5 seconds)
nowTime = new GetCurrentTimeStamp();
logData.add((String) TemData.get(counter));
System.out.println();
System.out.println("Outputting Array Data >> " + logData.get(counter));
//add to timestamp ArrayList
nowTime = new GetCurrentTimeStamp();
counter++; //increment counter)
}
This is GetCurrentTimeStamp class
public class GetCurrentTimeStamp {
public GetCurrentTimeStamp()
public GetCurrentTimeStamp() {
//Date object
Date date= new Date();
//getTime() returns current time in milliseconds
long time = date.getTime();
//Passed the milliseconds to constructor of Timestamp class
Timestamp ts = new Timestamp(time);
System.out.println("Time Stamp >> "+ts);
}
}
Why don't you create a simple class to store your values?
class MyData {
private String myString;
private Timestamp myTime;
MyData(String string, Timestamp timestamp) {
this.myString = string;
this.myTime = timestamp;
}
// getters and setters of your choosing
}
Then in your code, instead of
ArrayList<String> logData = new ArrayList<String>(); do a ArrayList<MyData> logData = new ArrayList<MyData>(); instead.
In your loop you could do something like
MyData myData = new MyData((String) TemData.get(counter), nowtime);
logData.add(myData);
... or tweak the actual add to the ArrayList based on which value of nowTime you wanted to use.
Multidimensional Arrays are possible, as are multidimensional ArrayLists, but I don't think that's what you need.
Just to reiterate what you're trying to do: You're trying to store a String and a Timestamp together. The simplest way of doing this with arrays is somewhat crude. You make two arrays: One for the Strings and one for the Timestamps, and you 'associate' values via their index. Eg:
ArrayList<String> strings = new ArrayList<String>();
ArrayList<Timestamp> times= new ArrayList<Timestamp>();
...
strings.get(5); // Your sixth logged entry
times.get(5); // and its associate timestamp
Like I said this is crude, and prone to errors because you need to ensure the indices match up at all times.
Another possibility is to use an associative collection of some sort. Hash maps come to mind. For example:
HashMap<Timestamp, String> logEntries = new HashMap<Timestamp, String>();
logEntries.put(GetCurrentTimeStamp(), (String) TemData.get(counter));
When searching/iterating through the collection, you would iterate through all of the keys in logEntries.keySet(). Eg:
for (Timestamp key : logEntries.keySet())
{
String value = logEntries.get(key);
// Do your processing here - you now know the key and value pair.
}

Categories