Calling Java function with arguments from StringTemplate? - java

StringTemplate allows programmers to fetch data through getters(a function with no arguments).
I would like to know that Is it possible to call Java function with arguments from String Template?

There is a workaround by abusing dictionaries. Here is an example of implementing "function" for limiting item count in a List (issue on github).
In your code add dictionary:
group.defineDictionary("max", new MaxListItemsLimiter());
Usage (in this example first item in array is max. items count):
<max.(["50",myObject.items]):{msg|<msg.something>}>
final class MaxListItemsLimiter extends AbstractMap<String, Object> {
#Override
public Object get(Object key) {
List items = (List) key;
if (!items.isEmpty()) {
//First item is max. count
Integer limit = NumberUtils.toInt(items.get(0).toString(), -1); //use Integer.parseInt
if (limit != -1) {
return items.subList(1, Math.min(items.size(), limit + 1));
} else {
throw new AssertionError("First parameter in max must be number");
}
} else {
return super.get(key);
}
}
#Override
public Set<Map.Entry<String, Object>> entrySet() {
return Collections.emptySet();
}
#Override
public boolean containsKey(Object key) {
if (key instanceof List) {
return true;
} else {
throw new AssertionError("You can use max only on Lists.");
}
}
}

Related

LinkedHashMap eldest entry giving null key,value

While trying to use a LinkedHashMap as a LRU cache, I am facing null pointer exceptions. A similar issue was discussed here, however my scenario is a bit different.
#Override
protected boolean removeEldestEntry(Map.Entry<K, CacheItem<V>> eldest)
{
if(size() >= maxEntriesOnHeap)
{
if (eldest.getValue() != null && eldest.getValue().isExpired(timeToLiveSecs))
{
offheap.put(eldest.getKey(), eldest.getValue());
}
return true;
}
return false;
}
The entry object is a wrapper object. What I found that if I do not provide the null check, it fails intermittently with the 'eldest' entry encountered having null key and null value. Proper synchronizations are in place.
So, is anyone aware of a scenario when an entry can exist with both key,value as null?
In a simple test case, this seems to work. Maybe you can point out the differences between this test and your implementation?
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashCacheTest
{
public static void main(String[] args)
{
Map<String, CacheItem<Integer>> map = create();
map.put("K0", new CacheItem<Integer>(0));
map.put("K1", new CacheItem<Integer>(1));
map.put("K2", new CacheItem<Integer>(2));
map.put("K3", new CacheItem<Integer>(3));
map.put("K4", new CacheItem<Integer>(4));
map.put("K5", new CacheItem<Integer>(5));
}
static class CacheItem<V>
{
V v;
CacheItem(V v)
{
this.v = v;
}
public boolean isExpired(double timeToLiveSecs)
{
return false;
}
#Override
public String toString()
{
return String.valueOf(v);
}
}
static <K, V> Map<K, CacheItem<V>> create()
{
Map<K, CacheItem<V>> map = new LinkedHashMap<K, CacheItem<V>>()
{
#Override
protected boolean removeEldestEntry(Map.Entry<K, CacheItem<V>> eldest)
{
int maxEntriesOnHeap = 5;
double timeToLiveSecs = 2;
if(size() >= maxEntriesOnHeap)
{
System.out.println("Removing : "+eldest.getKey()+", "+eldest.getValue());
if (eldest.getValue().isExpired(timeToLiveSecs))
{
System.out.println("To off-heap: "+eldest.getKey()+", "+eldest.getValue());
//offheap.put(eldest.getKey(), eldest.getValue());
}
return true;
}
return false;
}
};
return map;
}
}
In any case, the question may sound naive, but ... are you sure that there are no null keys used? A statement like
map.put(null, value);
will work in the first place...

Create an ArrayList of unique values [duplicate]

This question already has answers here:
Get unique values from ArrayList in Java
(9 answers)
Closed 2 years ago.
I have an ArrayList with values taken from a file (many lines, this is just an extract):
20/03/2013 23:31:46 6870 6810 6800 6720 6860 6670 6700 6650 6750 6830 34864 34272
20/03/2013 23:31:46 6910 6780 6800 6720 6860 6680 6620 6690 6760 6790 35072 34496
Where the first two values per line are strings that contain data and are stored in a single element.
What I want to do is compare the string data elements and delete, for example, the second one and all the elements referred to in that line.
For now, I've used a for loop that compares the string every 13 elements (in order to compare only data strings).
My question: can I implement other better solutions?
This is my code:
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) throws Exception{
//The input file
Scanner s = new Scanner(new File("prova.txt"));
//Saving each element of the input file in an arraylist
ArrayList<String> list = new ArrayList<String>();
while (s.hasNext()){
list.add(s.next());
}
s.close();
//Arraylist to save modified values
ArrayList<String> ds = new ArrayList<String>();
//
int i;
for(i=0; i<=list.size()-13; i=i+14){
//combining the first to values to obtain data
String str = list.get(i)+" "+list.get(i+1);
ds.add(str);
//add all the other values to arraylist ds
int j;
for(j=2; j<14; j++){
ds.add(list.get(i+j));
}
//comparing data values
int k;
for(k=0; k<=ds.size()-12; k=k+13){
ds.get(k); //first data string element
//Comparing with other strings and delete
//TODO
}
}
}
}
Try checking for duplicates with a .contains() method on the ArrayList, before adding a new element.
It would look something like this
if(!list.contains(data))
list.add(data);
That should prevent duplicates in the list, as well as not mess up the order of elements, like people seem to look for.
Create an Arraylist of unique values
You could use Set.toArray() method.
A collection that contains no duplicate elements. More formally, sets
contain no pair of elements e1 and e2 such that e1.equals(e2), and at
most one null element. As implied by its name, this interface models
the mathematical set abstraction.
http://docs.oracle.com/javase/6/docs/api/java/util/Set.html
HashSet hs = new HashSet();
hs.addAll(arrayList);
arrayList.clear();
arrayList.addAll(hs);
Pretty late to the party, but here's my two cents:
Use a LinkedHashSet
I assume what you need is a collection which:
disallows you to insert duplicates;
retains insertion order.
LinkedHashSet does this. The advantage over using an ArrayList is that LinkedHashSet has a complexity of O(1) for the contains operation, as opposed to ArrayList, which has O(n).
Of course, you need to implement your object's equals and hashCode methods properly.
//Saving each element of the input file in an arraylist
ArrayList<String> list = new ArrayList<String>();
while (s.hasNext()){
list.add(s.next());
}
//That's all you need
list = (ArrayList) list.stream().distinct().collect(Collectors.toList());
If you want to make a list with unique values from an existing list you can use
List myUniqueList = myList.stream().distinct().collect(Collectors.toList());
Use Set
...
Set<String> list = new HashSet<>();
while (s.hasNext()){
list.add(s.next());
}
...
You can easily do this with a Hashmap. You obviously have a key (which is the String data) and some values.
Loop on all your lines and add them to your Map.
Map<String, List<Integer>> map = new HashMap<>();
...
while (s.hasNext()){
String stringData = ...
List<Integer> values = ...
map.put(stringData,values);
}
Note that in this case, you will keep the last occurence of duplicate lines. If you prefer keeping the first occurence and removing the others, you can add a check with Map.containsKey(String stringData); before putting in the map.
You could use a Set. It is a collection which doesn't accept duplicates.
Solution #1: HashSet
A good solution to the immediate problem of reading a file into an ArrayList with a uniqueness constraint is to simply keep a HashSet of seen items. Before processing a line, we check that its key is not already in the set. If it isn't, we add the key to the set to mark it as finished, then add the line data to the result ArrayList.
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args)
throws FileNotFoundException, IOException {
String file = "prova.txt";
ArrayList<String[]> data = new ArrayList<>();
HashSet<String> seen = new HashSet<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
for (String line; (line = br.readLine()) != null;) {
String[] split = line.split("\\s+");
String key = split[0] + " " + split[1];
if (!seen.contains(key)) {
data.add(Arrays.copyOfRange(split, 2, split.length));
seen.add(key);
}
}
}
for (String[] row : data) {
System.out.println(Arrays.toString(row));
}
}
}
Solution #2: LinkedHashMap/LinkedHashSet
Since we have key-value pairs in this particular dataset, we could roll everything into a LinkedHashMap<String, ArrayList<String>> (see docs for LinkedHashMap) which preserves ordering but can't be indexed into (use-case driven decision, but amounts to the same strategy as above. ArrayList<String> or String[] is arbitrary here--it could be any data value). Note that this version makes it easy to preserve the most recently seen key rather than the oldest (remove the !data.containsKey(key) test).
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args)
throws FileNotFoundException, IOException {
String file = "prova.txt";
LinkedHashMap<String, ArrayList<String>> data = new LinkedHashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
for (String line; (line = br.readLine()) != null;) {
String[] split = line.split("\\s+");
String key = split[0] + " " + split[1];
if (!data.containsKey(key)) {
ArrayList<String> val = new ArrayList<>();
String[] sub = Arrays.copyOfRange(split, 2, split.length);
Collections.addAll(val, sub);
data.put(key, val);
}
}
}
for (Map.Entry<String, ArrayList<String>> e : data.entrySet()) {
System.out.println(e.getKey() + " => " + e.getValue());
}
}
}
Solution #3: ArrayListSet
The above examples represent pretty narrow use cases. Here's a sketch for a general ArrayListSet class, which maintains the usual list behavior (add/set/remove etc) while preserving uniqueness.
Basically, the class is an abstraction of solution #1 in this post (HashSet combined with ArrayList), but with a slightly different flavor (the data itself is used to determine uniqueness rather than a key, but it's a truer "ArrayList" structure).
This class solves the problems of efficiency (ArrayList#contains is linear, so we should reject that solution except in trivial cases), lack of ordering (storing everything directly in a HashSet doesn't help us), lack of ArrayList operations (LinkedHashSet is otherwise the best solution but we can't index into it, so it's not a true replacement for an ArrayList).
Using a HashMap<E, index> instead of a HashSet would speed up remove(Object o) and indexOf(Object o) functions (but slow down sort). A linear remove(Object o) is the main drawback over a plain HashSet.
import java.util.*;
public class ArrayListSet<E> implements Iterable<E>, Set<E> {
private ArrayList<E> list;
private HashSet<E> set;
public ArrayListSet() {
list = new ArrayList<>();
set = new HashSet<>();
}
public boolean add(E e) {
return set.add(e) && list.add(e);
}
public boolean add(int i, E e) {
if (!set.add(e)) return false;
list.add(i, e);
return true;
}
public void clear() {
list.clear();
set.clear();
}
public boolean contains(Object o) {
return set.contains(o);
}
public E get(int i) {
return list.get(i);
}
public boolean isEmpty() {
return list.isEmpty();
}
public E remove(int i) {
E e = list.remove(i);
set.remove(e);
return e;
}
public boolean remove(Object o) {
if (set.remove(o)) {
list.remove(o);
return true;
}
return false;
}
public boolean set(int i, E e) {
if (set.contains(e)) return false;
set.add(e);
set.remove(list.set(i, e));
return true;
}
public int size() {
return list.size();
}
public void sort(Comparator<? super E> c) {
Collections.sort(list, c);
}
public Iterator<E> iterator() {
return list.iterator();
}
public boolean addAll(Collection<? extends E> c) {
int before = size();
for (E e : c) add(e);
return size() == before;
}
public boolean containsAll(Collection<?> c) {
return set.containsAll(c);
}
public boolean removeAll(Collection<?> c) {
return set.removeAll(c) && list.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
return set.retainAll(c) && list.retainAll(c);
}
public Object[] toArray() {
return list.toArray();
}
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
}
Example usage:
public class ArrayListSetDriver {
public static void main(String[] args) {
ArrayListSet<String> fruit = new ArrayListSet<>();
fruit.add("apple");
fruit.add("banana");
fruit.add("kiwi");
fruit.add("strawberry");
fruit.add("apple");
fruit.add("strawberry");
for (String item : fruit) {
System.out.print(item + " "); // => apple banana kiwi strawberry
}
fruit.remove("kiwi");
fruit.remove(1);
fruit.add(0, "banana");
fruit.set(2, "cranberry");
fruit.set(0, "cranberry");
System.out.println();
for (int i = 0; i < fruit.size(); i++) {
System.out.print(fruit.get(i) + " "); // => banana apple cranberry
}
System.out.println();
}
}
Solution #4: ArrayListMap
This class solves a drawback of ArrayListSet which is that the data we want to store and its associated key may not be the same. This class provides a put method that enforces uniqueness on a different object than the data stored in the underlying ArrayList. This is just what we need to solve the original problem posed in this thread. This gives us the ordering and iteration of an ArrayList but fast lookups and uniqueness properties of a HashMap. The HashMap contains the unique values mapped to their index locations in the ArrayList, which enforces ordering and provides iteration.
This approach solves the scalability problems of using a HashSet in solution #1. That approach works fine for a quick file read, but without an abstraction, we'd have to handle all consistency operations by hand and pass around multiple raw data structures if we needed to enforce that contract across multiple functions and over time.
As with ArrayListSet, this can be considered a proof of concept rather than a full implementation.
import java.util.*;
public class ArrayListMap<K, V> implements Iterable<V>, Map<K, V> {
private ArrayList<V> list;
private HashMap<K, Integer> map;
public ArrayListMap() {
list = new ArrayList<>();
map = new HashMap<>();
}
public void clear() {
list.clear();
map.clear();
}
public boolean containsKey(Object key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
return list.contains(value);
}
public V get(int i) {
return list.get(i);
}
public boolean isEmpty() {
return map.isEmpty();
}
public V get(Object key) {
return list.get(map.get(key));
}
public V put(K key, V value) {
if (map.containsKey(key)) {
int i = map.get(key);
V v = list.get(i);
list.set(i, value);
return v;
}
list.add(value);
map.put(key, list.size() - 1);
return null;
}
public V putIfAbsent(K key, V value) {
if (map.containsKey(key)) {
if (list.get(map.get(key)) == null) {
list.set(map.get(key), value);
return null;
}
return list.get(map.get(key));
}
return put(key, value);
}
public V remove(int i) {
V v = list.remove(i);
for (Map.Entry<K, Integer> entry : map.entrySet()) {
if (entry.getValue() == i) {
map.remove(entry.getKey());
break;
}
}
decrementMapIndices(i);
return v;
}
public V remove(Object key) {
if (map.containsKey(key)) {
int i = map.remove(key);
V v = list.get(i);
list.remove(i);
decrementMapIndices(i);
return v;
}
return null;
}
private void decrementMapIndices(int start) {
for (Map.Entry<K, Integer> entry : map.entrySet()) {
int i = entry.getValue();
if (i > start) {
map.put(entry.getKey(), i - 1);
}
}
}
public int size() {
return list.size();
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public Set<Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> es = new HashSet<>();
for (Map.Entry<K, Integer> entry : map.entrySet()) {
es.add(new AbstractMap.SimpleEntry<>(
entry.getKey(), list.get(entry.getValue())
));
}
return es;
}
public Set<K> keySet() {
return map.keySet();
}
public Collection<V> values() {
return list;
}
public Iterator<V> iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
}
Here's the class in action on the original problem:
import java.io.*;
public class Main {
public static void main(String[] args)
throws FileNotFoundException, IOException {
String file = "prova.txt";
ArrayListMap<String, String[]> data = new ArrayListMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
for (String line; (line = br.readLine()) != null;) {
String[] split = line.split("\\s+");
String key = split[0] + " " + split[1];
String[] sub = Arrays.copyOfRange(split, 2, split.length);
data.putIfAbsent(key, sub);
}
}
for (Map.Entry<String, String[]> e : data.entrySet()) {
System.out.println(e.getKey() + " => " +
java.util.Arrays.toString(e.getValue()));
}
for (String[] a : data) {
System.out.println(java.util.Arrays.toString(a));
}
}
}
Just Override the boolean equals() method of custom object. Say you have an ArrayList with custom field f1, f2, ... override
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CustomObject)) return false;
CustomObject object = (CustomObject) o;
if (!f1.equals(object.dob)) return false;
if (!f2.equals(object.fullName)) return false;
...
return true;
}
and check using ArrayList instance's contains() method. That's it.
If you need unique values, you should use the implementation of the SET interface
You can read from file to map, where the key is the date and skip if the the whole row if the date is already in map
Map<String, List<String>> map = new HashMap<String, List<String>>();
int i = 0;
String lastData = null;
while (s.hasNext()) {
String str = s.next();
if (i % 13 == 0) {
if (map.containsKey(str)) {
//skip the whole row
lastData = null;
} else {
lastData = str;
map.put(lastData, new ArrayList<String>());
}
} else if (lastData != null) {
map.get(lastData).add(str);
}
i++;
}
I use helper class. Not sure it's good or bad
public class ListHelper<T> {
private final T[] t;
public ListHelper(T[] t) {
this.t = t;
}
public List<T> unique(List<T> list) {
Set<T> set = new HashSet<>(list);
return Arrays.asList(set.toArray(t));
}
}
Usage and test:
import static org.assertj.core.api.Assertions.assertThat;
public class ListHelperTest {
#Test
public void unique() {
List<String> s = Arrays.asList("abc", "cde", "dfg", "abc");
List<String> unique = new ListHelper<>(new String[0]).unique(s);
assertThat(unique).hasSize(3);
}
}
Or Java8 version:
public class ListHelper<T> {
public Function<List<T>, List<T>> unique() {
return l -> l.stream().distinct().collect(Collectors.toList());
}
}
public class ListHelperTest {
#Test
public void unique() {
List<String> s = Arrays.asList("abc", "cde", "dfg", "abc");
assertThat(new ListHelper<String>().unique().apply(s)).hasSize(3);
}
}

Make a unique list of objects Java

I have an ArrayList filled with objects with attributes name and time. I would like to remove duplicates based on the name and keep only records with the latest time. So I have overriden equals and hashcode for name in my object and used code like this.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
changedRecentlyList.clear(); //static list
for(ChangedRecentlyTO to : toList) {
if(!changedRecentlyList.contains(to)) {
changedRecentlyList.add(to);
} else {
if(changedRecentlyList.get(changedRecentlyList.lastIndexOf(to)).getTimeChanged().before(to.getTimeChanged())) {
changedRecentlyList.remove(to);
changedRecentlyList.add(to);
}
}
}
return changedRecentlyList;
}
But I am wondering, is there a better solution?I was thinking about using Set but I am not able to figure out how should I put there the time criterion.
You have to me two ways, one which requires understanding how the set work, and one which is more understandable for people who have littler understanding of Java Collections:
If you want to make it simple, you can simply read in the detail the Javadoc of Set, http://docs.oracle.com/javase/6/docs/api/java/util/Set.html#add(E). It clearly states that if an element is already inside, it won't be added again.
You implement your equals and hashcode using only the name
You sort the items by time and then you add them to the Set.
In such a way, the first time you will add the item to Set, you will be adding the elements with the latest times. When you'll add the others, they will be ignored because they are already contained.
If someone else who does not know exactly the contract of java.util.Set behaves, you might want to extend Set to make your intention clearer. However, since a Set is not supposed to be accessed to "get back an element after removal", you will need to back your set with an HashMap:
interface TimeChangeable {
long getTimeChanged();
}
public class TimeChangeableSet<E extends TimeCheangeable> implements Set<E> {
private final HashMap<Integer,E> hashMap = new HashMap<Integer,E>();
#Override
public boolean add(E e) {
E existingValue = hashMap.remove(e.hashCode());
if(existingValue==null){
hashMap.put(e.hashCode(),e);
return true;
}
else{
E toAdd = e.getTimeChanged() > existingValue.getTimeChanged() ? e : existingValue;
boolean newAdded = e.getTimeChanged() > existingValue.getTimeChanged() ? true : false;
hashMap.put(e.hashCode(),e);
return newAdded;
}
}
#Override
public int size() {
return hashMap.size();
}
#Override
public boolean isEmpty() {
return hashMap.isEmpty();
}
#Override
public boolean contains(Object o) {
return hashMap.containsKey(o.hashCode());
}
#Override
public Iterator<E> iterator() {
return hashMap.values().iterator();
}
#Override
public Object[] toArray() {
return hashMap.values().toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return hashMap.values().toArray(a);
}
#Override
public boolean remove(Object o) {
return removeAndGet(o)!=null ? true : false;
}
public E removeAndGet (Object o) {
return hashMap.remove(o.hashCode());
}
#Override
public boolean containsAll(Collection<?> c) {
boolean containsAll = true;
for(Object object:c){
E objectInMap = removeAndGet(object);
if(objectInMap==null || !objectInMap.equals(object))
containsAll=false;
}
return containsAll;
}
#Override
public boolean addAll(Collection<? extends E> c) {
boolean addAll=true;
for(E e:c){
if(!add(e)) addAll=false;
}
return addAll;
}
#Override
public boolean retainAll(Collection<?> c) {
boolean setChanged=false;
for(E e: hashMap.values()){
if(!c.contains(e)){
hashMap.remove(e.hashCode());
setChanged=true;
}
}
return setChanged;
}
#Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("Please do not use type-unsafe methods in 2012");
}
#Override
public void clear() {
hashMap.clear();
}
}
Extend HashMap and override put method to put only if new object is more recent than the existing one.
Or, you can create your own dedicated container which will be backed by a HashMap, just like some implementations of Stack are backed by LinkedList
This is a mock code:
import java.util.HashMap;
import java.util.Map;
public class TimeMap<K, V> {
private Map<K, V> timeMap;
public TimeMap() {
this.timeMap = new HashMap<K, V>();
}
public void put(K key, V value) {
if (isNewer(key, value)) {
this.timeMap.put(key, value);
}
}
}
Why you dont use a Set and later:
new ArrayList(set);
A very quick implementation of what I had in mind.
Assumed the ChangedRecentlyTO object had a name property.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
Map<String, ChangedRecentlyTO> uniqueMap = new HashMap<String, ChangedRecentlyTO>();
for(ChangedRecentlyTO to : toList) {
if (uniqueMap.containsKey(to.getName())) {
if (uniqueMap.get(to.getName()).getTimeChanged().before(to.getTimeChanged())) {
uniqueMap.put(to.getName(), to);
}
} else {
uniqueMap.put(to.getName(), to);
}
}
return (List<ChangedRecentlyTO>) uniqueMap.values();
}
After all of that, it doesn't seem to different to your original implementation with the exception that there is no need override hashcode and equals.
You could let your class implement the Comparable interface and make compare check the timestamps you are interested in. If you then sort it (e.g. put all the elements in a TreeSet) and then get them out one by one, only if they don't already exist. Something like this:
public void removeDuplicates(List<MyObject> list){
SortedSet<MyObject> sortedSet = new TreeSet<MyObject>();
sortedSet.addAll(list);
//Now clear the list, and start adding them again
list.clear();
for(MyObject obj : sortedSet){
if(!list.contains(obj) {
list.add(obj);
}
}
return list;
}
This, however, will only work if two objects with different timestamps are not equal! (in the equals() sense of the word
What I would suggest , Make your class Comparable by implementing Comparable interface.Then in comparetTo() based on name and time compare them if object time is recent return 1 else 0(if equal) or -1 .Once you got this functionality you can extend HashMap class and override the put method like.
o1.compareTo(o2) > 0 then simply overwrite the object with latest one.
Adding logic to #Lopina code like
public class MyHashMap extends HashMap<String, MyClass>{
private Map<String, MyClass> timeMap;
public MyHashMap() {
this.timeMap = new HashMap<String, MyClass>();
}
public MyClass put(String key, MyClass value) {
MyClass obj;
if (isNewer(key, value)) {
System.out.println("count");
obj=this.timeMap.put(key, value);
}else{
obj=value;
}
return obj;
}
private boolean isNewer(String key, MyClass value) {
if(this.timeMap.get(key)==null ||( key.equals(value.getName()))&& (this.timeMap.get(key).compareTo(value))<0)
return true;
else
return false;
}
#Override
public int size() {
return this.timeMap.size();
}
#Override
public MyClass get(Object key) {
return this.timeMap.get(key);
}
}
In MyClass implement comparable interface and override compareTo method like below.
#Override
public int compareTo(MyClass o) {
return this.getTime().compareTo(o.getTime());
}
I wrote a UniqueList class that extends an ArrayList to back its data and utilises a HashSet to efficiently reject duplicates. This gives O(1) Random Access Time and many other speed improvements to manually sweeping the dataset.
https://gist.github.com/hopesenddreams/80730eaafdfe816ddbb1
public class UniqueList<T> extends ArrayList<T> implements Set<T>
{
HashMap<T,Integer> hash; // T -> int
public UniqueList()
{
hash = new HashMap<>();
}
/*
* O(n)
* */
#Override
public void add(int location, T object)
{
super.add(location, object);
for( int i = location ; i < size() ; i++ )
{
hash.put(get(i),i);
}
}
/*
* O(1) amortized.
* */
#Override
public boolean add(T object) {
if( hash.containsKey(object) ) return false;
hash.put(object, size());
super.add(object);
return true;
}
/*
* O(MAX(collection.size(),n)) because of the hash-value-shift afterwards.
* */
#Override
public boolean addAll(int location, Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put(t, size());
super.add(t);
bChanged = true;
}
}
for( int i = location + collection.size() ; i < size() ; i ++ )
{
hash.put( get(i) , i );
}
return bChanged;
}
/*
* O(collection.size())
* */
#Override
public boolean addAll(Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put( t , size() );
super.add(t);
bChanged = true;
}
}
return bChanged;
}
/*
* O(n)
* */
#Override
public void clear() {
hash.clear();
super.clear();
}
/*
* O(1)
* */
#Override
public boolean contains(Object object) {
return hash.containsKey(object);
}
/*
* O(collection.size())
* */
#Override
public boolean containsAll(Collection<?> collection) {
boolean bContainsAll = true;
for( Object c : collection ) bContainsAll &= hash.containsKey(c);
return bContainsAll;
}
/*
* O(1)
* */
#Override
public int indexOf(Object object) {
//noinspection SuspiciousMethodCalls
Integer index = hash.get(object);
return index!=null?index:-1;
}
/*
* O(1)
* */
#Override
public int lastIndexOf(Object object)
{
return hash.get(object);
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public T remove(int location) {
T t = super.remove(location);
hash.remove( t );
for( int i = size() - 1 ; i >= location ; i -- )
{
hash.put( get(i) , i );
}
return t;
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public boolean remove(Object object) {
Integer i = hash.get( object );
if( i == null ) return false;
remove( i.intValue() );
return true;
}
/*
* O( MAX( collection.size() , ArrayList.removeAll(collection) ) )
* */
#Override
public boolean removeAll(#NonNull Collection<?> collection) {
for( Object c : collection )
{
hash.remove( c );
}
return super.removeAll( collection );
}
}

Real time sorted by value, auto-discarding, bounded collection ?

I spent some time to try to make a collection that:
1) is sorted by value (not by key)
2) is sorted each time an element is added or modified
3) is fixed size and discard automatically smallest/biggest element depending of the sort way
4) is safe thread
So 3) and 4) I think it is quite ok. For 1) and 2) it was a bit more tricky. I spent quite a long time on this thread, experimenting the different sample, but one big issue is that the collection are sorted only once when object are inserted.
Anyway, I try to implement my own collection, which is working (shouldn't be used for huge data as it is sorted quite often) but I'm not so happy with the design. Especially in the fact that my value objects are constrained to be Observable (which is good) but not comparable so I had to use a dirty instanceof + exception for this.
Any sugestion to improve this ?
Here is the code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class SortedDiscardingSyncArray<K, V extends Observable> implements Observer {
// Comparison way (ascendent or descendant)
public static enum ComparisonWay
{
DESC,
ASC;
}
// this is backed by a List (and ArrayList impl)
private List<ArrayElement> array;
// Capacity, configurable, over this limit, an item will be discarded
private int MAX_CAPACITY = 200;
// default is descending comparison
private ComparisonWay compareWay = ComparisonWay.DESC;
public SortedDiscardingSyncArray(ComparisonWay compareWay, int mAX_CAPACITY) {
super();
this.compareWay = compareWay;
MAX_CAPACITY = mAX_CAPACITY;
array = new ArrayList <ArrayElement>(MAX_CAPACITY);
}
public SortedDiscardingSyncArray(int mAX_CAPACITY) {
super();
MAX_CAPACITY = mAX_CAPACITY;
array = new ArrayList<ArrayElement>(MAX_CAPACITY);
}
public SortedDiscardingSyncArray() {
super();
array = new ArrayList <ArrayElement>(MAX_CAPACITY);
}
public boolean put(K key, V value)
{
try {
return put (new ArrayElement(key, value, this));
} catch (Exception e) {
e.printStackTrace();
return false;
}
finally
{
sortArray();
}
}
private synchronized boolean put(ArrayElement ae)
{
if (array.size() < MAX_CAPACITY)
{
return array.add(ae);
}
// check if last one is greater/smaller than current value to insert
else if (ae.compareTo(array.get(MAX_CAPACITY-1)) < 0)
{
array.remove(MAX_CAPACITY - 1);
return array.add(ae);
}
// else we don't insert
return false;
}
public V getValue (int index)
{
return array.get(index).getValue();
}
public V getValue (K key)
{
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key)) return ae.getValue();
}
return null;
}
public K getKey (int index)
{
return array.get(index).getKey();
}
private void sortArray()
{
Collections.sort(array);
}
public synchronized void setValue(K key, V newValue) {
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key))
{
ae.setValue(newValue);
return;
}
}
}
public int size() {
return array.size();
}
#Override
public void update(java.util.Observable arg0, Object arg1) {
sortArray();
}
public static void main(String[] args) {
// some test on the class
SortedDiscardingSyncArray<String, ObservableSample> myData = new SortedDiscardingSyncArray<String, ObservableSample>(ComparisonWay.DESC, 20);
String Ka = "Ka";
String Kb = "Kb";
String Kc = "Kc";
String Kd = "Kd";
myData.put(Ka, new ObservableSample(0));
myData.put(Kb, new ObservableSample(3));
myData.put(Kc, new ObservableSample(1));
myData.put(Kd, new ObservableSample(2));
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
System.out.println("Modifying data...");
myData.getValue(Kb).setValue(12);
myData.getValue(Ka).setValue(34);
myData.getValue(Kd).setValue(9);
myData.getValue(Kc).setValue(19);
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
}
private class ArrayElement implements Comparable <ArrayElement> {
public ArrayElement(K key, V value, Observer obs) throws Exception {
super();
// don't know how to handle that case
// maybe multiple inheritance would have helped here ?
if (! (value instanceof Comparable)) throw new Exception("Object must be 'Comparable'");
this.key = key;
this.value = value;
value.addObserver(obs);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(key);
sb.append(" - ");
sb.append(value);
return sb.toString();
}
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public synchronized void setValue(V value) {
this.value = value;
}
#SuppressWarnings("unchecked")
#Override
public int compareTo(ArrayElement o) {
int c;
if (compareWay == ComparisonWay.DESC) c = ((Comparable<V>) o.getValue()).compareTo(this.getValue());
else c = ((Comparable<V>) this.getValue()).compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
}
And the other class for testing purpose:
import java.util.Observable;
public class ObservableSample extends Observable implements Comparable <ObservableSample>
{
private Integer value = 0;
public ObservableSample(int value) {
this.value = value;
setChanged();
notifyObservers();
}
public String toString()
{
return String.valueOf(this.value);
}
public void setValue(Integer value) {
this.value = value;
setChanged();
notifyObservers();
}
public Integer getValue() {
return value;
}
#Override
public int compareTo(ObservableSample o) {
int c;
c = (this.getValue()).compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
Collections are difficult to write, maybe you should look for an existing implementation.
Try checking out ImmutableSortedSet from Guava.
You can have a marker interface
public interface ComparableObservable extends Observable, Comparable {
}
and then change
SortedDiscardingSyncArray<K, V extends Observable>
to
SortedDiscardingSyncArray<K, V extends ComparableObservable>
to avoid the explicit cast.
Other than that the code is quite verbose and I didn't follow it completely. I would also suggest having a look at guava or (apache) commons-collections library to explore if you can find something reusable.
You can write generic wildcards with multiple bounds. So change your declaration of <K, V extends Observable> to <K, V extends Observable & Comparable<V>> and then you can treat V as if it implements both interfaces, without an otherwise empty and useless interface.
Another few things: Pick a naming convention, and stick with it. The one I use is that a name such as MAX_CAPACITY would be used for a static final field (i.e. a constant, such as a default) and that the equivalent instance field would be maxCapacity Names such as mAX_CAPACITY would be right out of the question.
See: Oracle's naming conventions for Java
Instead of using a ComparisonWay enum, I would take a custom Comparator. Much more flexible, and doesn't replicate something that already exists.
See: the Comparator API docs
Your code, as written, is not thread safe. In particular an observed element calling the unsynchronized update method may thus invoke sortArray without obtaining the proper lock. FindBugs is a great tool that catches a lot of problems like this.
Your ObservableSample does not really follow good practices with regards to how it implements Comparable, in that it does not really compare data values but instead the hashCode. The hashCode is essentially arbitrary and collisions are quite possible. Additionally, the Comparable interface requests that usually you should be "consistent with Equals", for which you also might want to take a look at the documentation for the Object class's equals method
Yes, it sounds like a lot of work, but if you go through it and do it right you will save yourself astounding amounts of debugging effort down the road. If you do not do these properly and to the spec, you will find that when you place it in Sets or Maps your keys or values strangely disappear, reappear, or get clobbered. And it will depend on which version of Java you run, potentially!
Here is a version updated. Still not completly sure it is safe thread but findbugs tool didn't give so usefull tips. Also for the comparisonWay, I don't want to constraint the user to develop its own comparator, I want to keep the things simple.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class SortedDiscardingSyncArray<K, V extends Observable & Comparable<V>> implements Observer {
// Comparison way (ascendent or descendant)
public static enum ComparisonWay { DESC, ASC; }
// this is backed by a List (and ArrayList)
private List<ArrayElement> array;
// Capacity, configurable, over this limit, an item will be discarded
private int maxCapacity = 200;
// default is descending comparison
private ComparisonWay compareWay = ComparisonWay.DESC;
public SortedDiscardingSyncArray(ComparisonWay compareWay, int maxCapacity) {
super();
this.compareWay = compareWay;
this.maxCapacity = maxCapacity;
array = new ArrayList <ArrayElement>(maxCapacity);
}
public SortedDiscardingSyncArray(int maxCapacity) {
super();
this.maxCapacity = maxCapacity;
array = new ArrayList<ArrayElement>(maxCapacity);
}
public SortedDiscardingSyncArray() {
super();
array = new ArrayList <ArrayElement>(maxCapacity);
}
// not synchronized, but calling internal sync put command
public boolean put(K key, V value)
{
try {
return put (new ArrayElement(key, value, this));
} catch (Exception e) {
e.printStackTrace();
return false;
}
finally
{
sortArray();
}
}
private synchronized boolean put(ArrayElement ae)
{
if (array.size() < maxCapacity) return array.add(ae);
// check if last one is greater/smaller than current value to insert
else if (ae.compareTo(array.get(maxCapacity-1)) < 0)
{
array.remove(maxCapacity - 1);
return array.add(ae);
}
// else we don't insert and return false
return false;
}
public V getValue (int index)
{
return array.get(index).getValue();
}
public V getValue (K key)
{
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key)) return ae.getValue();
}
return null;
}
public K getKey (int index)
{
return array.get(index).getKey();
}
private synchronized void sortArray()
{
Collections.sort(array);
}
public synchronized void setValue(K key, V newValue) {
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key))
{
ae.setValue(newValue);
return;
}
}
}
public int size() {
return array.size();
}
#Override
public void update(java.util.Observable arg0, Object arg1) {
sortArray();
}
public static void main(String[] args) {
// some test on the class
SortedDiscardingSyncArray<String, ObservableSample> myData = new SortedDiscardingSyncArray<String, ObservableSample>(ComparisonWay.DESC, 20);
String Ka = "Ka";
String Kb = "Kb";
String Kc = "Kc";
String Kd = "Kd";
myData.put(Ka, new ObservableSample(0));
myData.put(Kb, new ObservableSample(3));
myData.put(Kc, new ObservableSample(1));
myData.put(Kd, new ObservableSample(2));
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
System.out.println("Modifying data...");
myData.getValue(Kb).setValue(12);
myData.getValue(Ka).setValue(34);
myData.getValue(Kd).setValue(9);
myData.getValue(Kc).setValue(19);
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
}
private class ArrayElement implements Comparable <ArrayElement> {
public ArrayElement(K key, V value, Observer obs) throws Exception {
super();
this.key = key;
this.value = value;
value.addObserver(obs);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(key);
sb.append(" - ");
sb.append(value);
return sb.toString();
}
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public synchronized void setValue(V value) {
this.value = value;
}
#Override
public int compareTo(ArrayElement o) {
int c;
if (compareWay == ComparisonWay.DESC) c = o.getValue().compareTo(this.getValue());
else c = this.getValue().compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
}

Java: iterating through list of lists?

The question but in C#. So does Java have C#'s command? I need it for Matches-SearchTerm-Files-relationship.
foreach(var i in BunchOfItems.SelectMany(k => k.Items)) {}
[Why not for-loops?]
I have done such structures in nested for loops but they soon become bloated. So I prefer something more succint like the above.
public static Stack<Integer[]> getPrintPoss(String s,File f,Integer maxViewPerF)
{
Stack<File> possPrint = new Stack<File>();
Integer[] poss = new Integer[4]();
int u,size;
for(File f:files)
{
size = f2S(f).length();
u = Math.min(maxViewsPerF,size);
for(int i=0; i<u;i++)
{
// Do something --- bloated, and soon out of control
// wants more succintly
}
}
return possPrint;
}
for (List<Object> lo : list) {
for (Object o : lo) {
// etc etc
}
}
I don't think there's a simpler solution.
If you can get the data into an Iterable<Iterable<T>>, then you can get from that to a flattened Iterable<T> using Guava's Iterables.concat method. If what you have is really an Iterable<S>, with some way to get from an S to an Iterable<T>, well, then you have to first use Iterables.transform to view that as the Iterable<Iterable<T>> needed by concat.
All this will look a lot nicer if and when Java has something resembling closures, but at least today it's possible.
http://guava-libraries.googlecode.com
With Java 8, you can say
Collection bunchOfItems = ...;
bunchOfItems.stream().flatMap(k::getItems).forEach(i -> /* operate on i */);
or
Item[] bunchOfItems = ...;
Stream.of(bunchOfItems).flatMap(k::getItems).forEach(i -> /* operate on i */);
depending upon whether you have a Collection or an Array.
Have about half a year patience until JDK7 is final which will include Closures. This provides simliar syntax and the same possibilities as LINQ which was demonstrated in the answer you're talking about.
I have my own version. Waiting desperately for Closures in Java :
public static <T, E> Iterable<T> transformMany(Iterable<E> iterable, Func<E, Iterable<T>> f) {
if (null == iterable)
throw new IllegalArgumentException("null iterable");
if (null == f)
throw new IllegalArgumentException("null f");
return new TransformManyIterable<E, T>(iterable, f);
}
public interface Func<E, T> {
T execute(E e);
}
public class TransformManyIterable<TOriginal, TResult> implements Iterable<TResult> {
private Iterable<TOriginal> iterable;
private Func<TOriginal, Iterable<TResult>> func;
public TransformManyIterable(Iterable<TOriginal> iterable,
Func<TOriginal, Iterable<TResult>> func) {
super();
this.iterable = iterable;
this.func = func;
}
class TransformIterator implements Iterator<TResult> {
private Iterator<TOriginal> iterator;
private Iterator<TResult> currentIterator;
public TransformIterator() {
iterator = iterable.iterator();
}
#Override
public boolean hasNext() {
if (currentIterator != null && currentIterator.hasNext())
return true;
else {
while (iterator.hasNext()) {
Iterable<TResult> iterable = func.execute(iterator.next());
if (iterable == null)
continue;
currentIterator = iterable.iterator();
if (currentIterator.hasNext())
return true;
}
}
return false;
}
#Override
public TResult next() {
if (currentIterator != null && currentIterator.hasNext())
return currentIterator.next();
else {
while (iterator.hasNext()) {
Iterable<TResult> iterable = func.execute(iterator.next());
if (iterable == null)
continue;
currentIterator = iterable.iterator();
if (currentIterator.hasNext())
return currentIterator.next();
}
}
throw new NoSuchElementException();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
#Override
public Iterator<TResult> iterator() {
return new TransformIterator();
}
}
Usage:
Iterable<SomeType> result = transformMany(input, new Func<InputType, Iterable<SomeType>>() {
#Override
public Iterable<SomeType> execute(InputType e) {
return new ArrayList<SomeType>();
}
});
The SelectMany method is part of LINQ which is .Net-specific. This question asks about a LINQ equilvalent for java. Unfortunately, it doesn't look like there is a direct equivalent.

Categories

Resources