This question already has answers here:
How to find an object in an ArrayList by property
(8 answers)
Closed 4 years ago.
I am maintaining a sorted ArrayList of objects (by overwriting the add method as shown here) where each object has 2 attributes: a and b. How can I retrieve an object for which a equals 5?
I cannot use a map, because the value which I want to sort the list on must be able to accept duplicates (which is why this answer is not applicable here).
Code:
class TimeMap {
List<MyType> list = new ArrayList<KVT>() {
public boolean add(KVT mt) {
int index = Collections.binarySearch(this, mt, new SortByTime());
if (index < 0) index = ~index;
super.add(index, mt);
return true;
}
};
}
class KVT{//value-timestamp object
String value;
int timestamp;
public VT(String v, int t){
value=v;
timestamp=t;
}
}
class SortByTimestamp implements Comparator<KVT>{
public int compare(KVT a, KVT b){
return a.timestamp.compareTo(b.timestamp);
}
}
I have written a small example using java8 streams where you can get the object from the ArrayList by a property of the object.
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Test> list = Arrays.asList(new Test(1, 2), new Test(5, 6), new Test(3, 4));
Test test = list.stream().filter(obj -> obj.a == 5).findFirst().orElse(null);
System.out.println(test.a);
}
}
class Test {
int a;
int b;
Test(int a, int b) {
this.a = a;
this.b = b;
}
}
Hope this will give you an idea
Here is an mcve demonstrating retrieval by timestamp as well as some other enhancement:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class TimeMap {
private List<KVT> list;
TimeMap() {
list = new ArrayList<>() {
#Override
public boolean add(KVT mt) {
super.add(mt); //add
Collections.sort(this, new SortByTimestamp()); //resort after add
return true;
}
};
}
boolean add(KVT mt){return list.add(mt);}
KVT getByTimeStamp(int timestamp){
for(KVT mt : list){
if(timestamp == mt.timestamp)
return mt;
}
return null;
}
//returns a copy of list
List<KVT> getListCopy() { return new ArrayList<>(list) ;};
//test
public static void main(String[] args) {
TimeMap tm = new TimeMap();
tm.add(new KVT("A", 2));
tm.add(new KVT("B", -3));
tm.add(new KVT("C", 1));
System.out.println(tm.getListCopy());
System.out.println(tm.getByTimeStamp(1));
}
}
class KVT{
String value;
int timestamp;
public KVT(String v, int t){
value=v;
timestamp=t;
}
#Override
public String toString(){ return value+" ("+timestamp+")";}
//todo add getters
}
class SortByTimestamp implements Comparator<KVT>{
#Override
public int compare(KVT a, KVT b){
//compareTo can not be applied to primitives
return Integer.valueOf(a.timestamp).compareTo(b.timestamp);
}
}
Related
Below is my code (can be copy paste in https://www.compilejava.net/ with -ea as command line option).
I have an Object called Main. I have Main inside a List. If 2 properties (a and b) are equal to another Main object in the list, property strings should be concatenated. Furthermore, duplicates (when the 2 properties are equal) should than be removed (so the list can not contain 2 or more Mains in which both a and b are the same).
I tried it with a HashMap, hashCode, but I can not figure it out well. Note: I use OpenJDK-12 and can not use newer versions.
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Main {
final int a;
final int b;
final List<String> strings;
Main(int a, int b, List<String> strings) {
this.a = a;
this.b = b;
this.strings = strings;
}
private static Main generateMain0() {
return new Main(0, 1, createListWithOneElement("merge me with main1"));
}
public static void main(String[] args) {
Main main0 = generateMain0();
Main main1 = new Main(0, 1, createListWithOneElement("merge me with main2"));
Main main2 = new Main(0, 2, createListWithOneElement("leave me alone"));
Main main3 = new Main(0, 2, createListWithOneElement("leave me alone also"));
List<Main> mains = new ArrayList<>();
mains.add(main0);
mains.add(main1);
mains.add(main2);
mains.add(main3);
// Do magic here to remove duplicate and concat property strings
// main1 should be removed, since property a and b were equal to main0 property a and b
assert mains.size() == 3;
Main main0Copy = generateMain0();
main0Copy.strings.add("merge me with main2");
// The first element should be main0. It should also contain
// the strings of main1 since property a and b were equal
assert mains.get(0).equals(main0Copy);
assert mains.get(1).equals(main2);
assert mains.get(2).equals(main3);
}
private static List<String> createListWithOneElement(String value) {
List<String> l = new ArrayList<>();
l.add(value);
return l;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Main main = (Main) o;
return a == main.a &&
b == main.b &&
strings.equals(main.strings);
}
#Override
public int hashCode() {
return Objects.hash(a, b, strings);
}
}
If, as you said in the comments, you can use a fully custom List, you can try the code below.
Internally, it uses a combination of a List and a Map to find out if a combination of a and b was already added to the "List". If yes, it adds all strings of the given Main to the existing Main. If not, it adds the given Main the the list.
package example;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainList {
private final List<Main> mains;
private final Map<Key, Main> lookup;
public MainList() {
this.mains = new ArrayList<>();
this.lookup = new HashMap<>();
}
public Main get(int index) {
return this.mains.get(index);
}
public void add(Main main) {
final Key key = new Key(main.a, main.b);
Main existingMain = this.lookup.get(key);
if (existingMain == null) {
this.mains.add(main);
this.lookup.put(key, main);
} else {
existingMain.strings.addAll(main.strings);
}
}
public void remove(Main main) {
final Key key = new Key(main.a, main.b);
Main existingMain = this.lookup.get(key);
if (existingMain != null) {
if (existingMain.equals(main)) {
this.mains.remove(existingMain);
this.lookup.remove(key);
} else {
existingMain.strings.removeAll(main.strings);
}
}
}
public void remove(int index) {
final Main removedMain = this.mains.remove(index);
final Key key = new Key(removedMain.a, removedMain.b);
this.lookup.remove(key);
}
public int size() {
return this.mains.size();
}
private static class Key {
private final int a;
private final int b;
private Key(int a, int b) {
this.a = a;
this.b = b;
}
#Override
public boolean equals(Object object) {
if (this == object) {
return true;
} else if (object == null || getClass() != object.getClass()) {
return false;
}
Key key = (Key) object;
return this.a == key.a && this.b == key.b;
}
#Override
public int hashCode() {
return 31 * this.a + 31 * this.b;
}
}
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PowerSet {
public static final <E> Collection<Set<E>> of(Set<E> s) {
List<E> src = new ArrayList<>(s);
if (src.size() > 30) {
throw new IllegalArgumentException("Set too big " + s);
}
return new AbstractList<Set<E>>() {
#Override
public int size() {
return 1 << src.size(); // 2 to the power srcSize
}
#Override
public boolean contains(Object o) {
return o instanceof Set && src.containsAll((Set) o);
}
#Override
public Set<E> get(int index) {
Set<E> result = new HashSet<>();
for (int i = 0; index != 0; i++, index >>= 1) {
if ((index & 1) == 1) {
result.add(src.get(i));
}
}
return result;
}
};
}
public static void main(String[] args) {
Collection<Set<String>> set = new HashSet<>();
set.add()... }
I have this code I got from Java Effective as how implement
power set but I am confused how to initialise this set and
fill it with values. There is interface with three overridden
methods, concretely contains, get and size. What does of in class
declaration mean?
To initialize PowerSet instance you need to call it's constructor PowerSet(), though it'll be useless since there is no object related underlying logic in it.
"of" is a static method declared in PowerSet, accepting a set with size <= 30 and returning a List of Sets with logic of power set.
It is implemented by extension of AbstractList.
Set<Long> input = new HashSet<Long>();
input.add(1L);
input.add(2L);
List<Set<Long>> example = PowerSet.<Long>of(input);
So, example.get(0) will result with an empty HashSet, example.get(1) == {1}; example.get(2) == {2}, example.get(3) == {1, 2}
You can rewrite it in a more conventional format:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PowerSet<E> extends AbstractList<Set<E>> {
private List<E> src;
public PowerSet(Set<E> s){
//copying set contains to a list to access by index
src = new ArrayList<>(s);
}
#Override
public int size() {
return 1 << src.size(); // 2 to the power srcSize
}
#Override
public boolean contains(Object o) {
return o instanceof Set && src.containsAll((Set) o);
}
#Override
public Set<E> get(int index) {
Set<E> result = new HashSet<>();
for (int i = 0; index != 0; i++, index >>= 1) {
if ((index & 1) == 1) {
result.add(src.get(i));
}
}
return result;
}
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add()...
PowerSet<String> = new PowerSet(set);
}
This question already has answers here:
Static method invocation
(5 answers)
Can I call a static method of another class without using the class name?
(3 answers)
Closed 4 years ago.
I have an issue with this code. It throws a "The method collectFrom(List < Integer> ) is undefined for the type Main" error, and I don't really know where's the problem.
The selector from "test1" method should choose from the list numbers lesser than 10, and mapper should increase those chosen numbers by 10.
import java.util.*;
public class Main {
public Main() {
List<Integer> src1 = Arrays.asList(1, 7, 9, 11, 12);
System.out.println(test1(src1));
}
public List<Integer> test1(List<Integer> src) {
Selector<Integer> sel = new Selector<Integer>() {
#Override
public boolean select(Integer a) {
if(a < 10) {
return true;
} else {
return false;
}
}
};
Mapper<Integer> map = new Mapper<Integer>() {
#Override
public Integer map(Integer a) {
return a+=10;
}
};
return collectFrom(src).when(sel).mapEvery(map);
}
public static void main(String[] args) {
new Main();
}
}
And this is my class ListCreator:
import java.util.ArrayList;
import java.util.List;
public class ListCreator <T>{
List<T> lista;
private ListCreator(List<T> src) {
this.lista = src;
}
public static <T> ListCreator<T> collectFrom(List<T> src) {
ListCreator<T> ls = new ListCreator<T>(src);
return ls;
};
public ListCreator<T> when(Selector s) {
List<T> whenLista = new ArrayList<T>();
for(int i = 0; i < lista.size(); ++i) {
if(s.select(lista.get(i))) {
whenLista.add(lista.get(i));
}
}
this.lista = whenLista;
return this;
};
public List<Integer> mapEvery (Mapper m) {
List<Integer> mapLista = new ArrayList<Integer>();
for(int i = 0; i < lista.size(); ++i) {
mapLista.add((Integer)m.map(lista.get(i)));
}
return mapLista;
}
}
Selector and Mapper are just simple, parameterized interfaces.
collectFrom is a static method defined in theListCreatorclass, not inMain`. You could qualify the call:
return ListCreator.collectFrom(src).when(sel).mapEvery(map);
Or just statically import it:
import static mypackage.ListCreator.collectFrom;
I've been trying to find possible answers, but found none.
I've got an ArrayList full of custom objects. One of their fields is a boolean.
I want to put this object first, keeping the rest of elements
For instance, if I've got this list and obj5 is the one with this boolean set to true:
obj3, obj2, obj5, obj7, obj9
I'd like to get this:
obj5, obj3, obj2, obj7, obj9
EDIT: CAN'T USE LAMBDAS, JAVA 6
EDIT 2: PLEASE NOTE THAT THE REST OF THE LIST MUST KEEP THE OLD ORDER
EDIT 3: In short words, I need this program to output [B, A, C, D, E]:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Trip {
#Override
public String toString() {
return name;
}
private String name;
private boolean freeCancellation;
public Trip(String name, boolean freeCancellation) {
this.name = name;
this.freeCancellation = freeCancellation;
}
static Comparator<Trip> myOrder = new Comparator<Trip>() {
public int compare(Trip a, Trip b) {
if (a.freeCancellation == b.freeCancellation) return 0;
return a.freeCancellation ? -1 : 1;
}
};
public static void main(String [] args){
Trip t1 = new Trip("A", false);
Trip t2 = new Trip("B", true);
Trip t3 = new Trip("C", false);
Trip t4 = new Trip("D", true);
Trip t5 = new Trip("E", false);
List<Trip> tripList = new ArrayList<>();
tripList.add(t1);
tripList.add(t2);
tripList.add(t3);
tripList.add(t4);
tripList.add(t5);
System.out.println(Arrays.toString(tripList.toArray()));
Collections.sort(tripList, myOrder);
//result should be [B, A, C, D, E]
System.out.println(Arrays.toString(tripList.toArray()));
}
}
Write a Comparator.
Comparator<MyType> myOrder = new Comparator<MyType>() {
public int compare(MyType a, MyType b) {
return (b.booleanField() ? 1 : 0) - (a.booleanField() ? 1 : 0);
}
}
Sort using this comparator.
Collections.sort(myList, myOrder);
See Collections.sort
Edit
So it seems that what you're actually asking for is to move just one matching element to the front of your list. That ought to be pretty easy.
Find the index of the element you want to move:
int foundIndex = -1;
for (int i = 0; i < tripList.size(); ++i) {
if (tripList.get(i).freeCancellation) {
foundIndex = i;
break;
}
}
If you find such an element, and it is not already at the start, move it to the start:
if (foundIndex > 0) {
tripList.add(0, tripList.remove(foundIndex));
}
List<Object> objList = findObj(name);Collections.sort(objList, new Comparator<Object>() {
#Override
public int compare(Object a1, Object a2) {
return (a1.getBooleanField()== a2.getBooleanField())?0:(a1.getBooleanField()?1:-1);
}});
This might help you to resolve this. You modify the results by changing the compare logic
Here is an example of how to achieve this:
class Element {
public boolean shouldBeFirst();
}
List<Element> elements;
elements.sort(Comparator.comparing(Element::shouldBeFirst));
This works because the natural ordering of booleans is true first.
If you can't use Java 8 then the equivalent would be something like:
Collections.sort(elements, new Comparator() {
int compareTo(Element el1, Element el2) {
return (el1.shouldBeFirst() ? 1 : 0) - (el2.shouldBeFirst() ? 1 : 0);
}
}
import java.util.*;
public class Test {
public static void main(String[] args) {
List<A> list = new ArrayList<A>();
list.add(new A(true));
list.add(new A(false));
list.add(new A(true));
list.add(new A(false));
Collections.sort(list);
System.out.println(list);
}
}
class A implements Comparable<A> {
private boolean b;
public A(boolean b) {
this.b = b;
}
public boolean isB() {
return b;
}
public void setB(boolean b) {
this.b = b;
}
#Override
public int compareTo(A a) {
return a.isB() ? 1 : -1;
}
#Override
public String toString() {
return "A [b=" + b + "]";
}
}
Maybe this is what you are looking for.
This is solution if you want to give natural ordering to object, then implement Comparable and use Collections.sort - https://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#sort(java.util.List).
If you have various members inside class, then maybe go with Comparator implementation, that way you can achieve many ways of sorting your objects based on different members.
If I understood what are you asking ,you need to create a new class called "Comparators".
in this class you need to define your methods and they need to be static final ...
then you can use it by calling to Collections.sort(-your array-, Comparator method name);
This question already has answers here:
cannot be cast to java.lang.Comparable
(2 answers)
Closed 8 years ago.
I want to sort an arraylist which contains "Counter" objects with Collections.sort() method. I have implemented the comparable interface in the Counter class. Still i get a class cast exception. I have posted the code below.
public class Counter implements Comparable<Counter>, java.io.Serializable {
private String description;
public Counter() {
}
public Counter(String description) {
this.description = description;
}
public int compareTo(Counter other) {
return description.compareTo(other.description);
}
}
The below method is where i call the sort method.
protected List < Counter > prepareCounters(final Integer authorityID) throws ServiceException {
if (authorityID == null) {
return new ArrayList < Counter >();
}
List < Counter > countersInRegistry = new ArrayList < Counter >(counterRegistry.getAllCounters());
List < Counter > countersFromService =
new ArrayList < Counter >(counterService.searchCounters(authorityID, null, null));
countersFromService.removeAll(countersInRegistry);
Collections.sort(countersFromService);
return countersFromService;
}
Is working for me, (OpenJDK7)>
// Main ----------------------------------------------------
package stackover_basic;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class StackOver_basic {
public static void main(String[] args) {
List<Counter> asList = Arrays.asList(new Counter("xx"), new Counter("aa"), new Counter("zz"));
System.out.println("before" + asList);
Collections.sort(asList);
System.out.println("after" + asList);
}
}
// Counter -------------------------------------------------
public class Counter implements Comparable<Counter>, java.io.Serializable {
private String description;
public Counter() {
}
public Counter(String description) {
this.description = description;
}
#Override
public int compareTo(Counter other) {
return description.compareTo(other.description);
}
#Override
public String toString() {
return "Counter{" + "description=" + description + '}';
}
}
Output>
run:
before[Counter{description=xx}, Counter{description=aa}, Counter{description=zz}]
after[Counter{description=aa}, Counter{description=xx}, Counter{description=zz}]
EDIT: Is highly possible that the classCastExc comes from your definition of compareTo. The reason: Your are adding a wrong object to the collection, i.e the return types of the methods counterService.searchCounters and counterRegistry.getAllCounters are not generic in Counter class.