I've created the following structure which maps unique double values to one or more pairs of integers:
#SuppressWarnings("boxing")
private static final HashMap<Double, Integer[][]> rules =
new HashMap<Double, Integer[][]>() {
private static final long serialVersionUID = 1L;
{
put(-0.6, new Integer[][] { { 1, 3 } });
put(-0.3, new Integer[][] { { 2, 2 } });
put(0.0, new Integer[][] { { 2, 4 }, { 3, 3 }, { 4, 2 } });
put(0.3, new Integer[][] { { 4, 4 } });
put(0.6, new Integer[][] { { 5, 3 } });
}
};
Can I rewrite this so it's simpler - i.e not have to deal with warnings (serialVersionUID, boxing), and it being so verbose?
Using a class for the pairs of integers should be the first. Or is this a coincidence, that all arrays containing a bunch of pairs?
The second thing is, that these initialization-data could be read from a configuration-file.
Edit: As I looked again on this code, I realized that Doubles as keys in a Map is somewhat risky. If you produce Doubles as a result of an mathematical operation, it is not clear, if they will be equal for the computer (even if they are equal in a mathematical sense). Floating-point-numbers are represented as approximation in computers. Most likely you want to associate the values with the interval (example 0.0-0.3) and not the value itself. You may avoid trouble, if you always use the same constants as keys in the array. But in this case you could use an enum as well, and no new programmer runs into trouble, if he uses his calculated doubles as keys in the map.
Create another class to hold your pairs of integers, and store them using a list:
Map<Double,List<MyPair>>
Are these to be arbitrary pairs of integers, or will the represent something? If the latter, then name appropriately. New classes are cheap in Java, and good naming will reduce maintenance costs.
Edit: why are you creating an anonymous subclass of HashMap?
Can you wrap a class around Integer[][] called, say Point?
That would make you have a
HashMap<Double, List<Point>>
using a static initializer would be slightly better in my opinion, although it does nothing about the verbosity:
private static final Map<Double, int[][]> rules;
static {
rules = new HashMap<Double, int[][]>();
rules.put(-0.6, new int[][] { { 1, 3 } });
rules.put(-0.3, new int[][] { { 2, 2 } });
rules.put(0.0, new int[][] { { 2, 4 }, { 3, 3 }, { 4, 2 } });
rules.put(0.3, new int[][] { { 4, 4 } });
rules.put(0.6, new int[][] { { 5, 3 } });
}
Another option using a special Pair class and Arrays.asList:
class Pair<A, B> {
A a;
B b;
public Pair(A fst, B snd) {
}
// getters and setters here
}
private static final Map<Double, List<Pair<Integer, Integer>>> rules;
static {
rules = new HashMap<Double, List<Pair<Integer, Integer>>>();
rules.put(-0.6, Arrays.asList(new Pair(1, 3)));
rules.put(-0.3, Arrays.asList(new Pair(2, 2)));
rules.put(0.0, Arrays.asList(new Pair(2, 4), new Pair(3, 3), new Pair(4, 2));
// etc
}
I would start with a MultiValueMap. http://larvalabs.com/collections/.
This way you can do:
private static final MultiValueMap<Double, Integer[]> rules;
static {
MultiValueMap<Double, Integer[]> map = new MultiValueMap <Double, Integer[]>();
map.put(-0.6, new Integer[] { 1, 3 });
map.put(-0.3, new Integer[] { 2, 2 });
map.put(0.0, new Integer[] { 2, 4 }, new Integer[]{ 3, 3 }, new Integer[]{ 4, 2 } );
map.put(0.3, new Integer[] { 4, 4 } );
map.put(0.6, new Integer[] { 5, 3 } );
rules = map;
};
It looks also like you are aways using pairs of integers as the list of Keys. It would probably clean your interface up if you refered to that as a RulePair or some other specified object. Thus 'typing' your Integer array more specificially.
There's not much you can do here. The warnings have to be suppressed; in practice, you never have to worry about serialVersionUID unless you are in fact planning to serialize this object.
The boxing can (and probably should) be removed by using a typed collection as described in other answers here. To remove the boilerplate, you'll have to use a method. For example:
private static void put (double key, int x, int y) {
rules.put(key, new Point(x,y));
}
you could try also with a Builder; Java is not good as other languages for this kind of uses.. but here is FYI:
First shot
class RuleBuilder {
private Map<Double, Integer[][]> rules;
public RuleBuilder() {
rules = new HashMap<Double, Integer[][]>();
}
public RuleBuilder rule(double key, Integer[]... rows) {
rules.put(key, rows);
return this;
}
public Integer[] row(Integer... ints) {
return ints;
}
public Map<Double, Integer[][]> build() {
return rules;
}
}
sample usage:
private static final Map<Double, Integer[][]> rules =
new RuleBuilder() {{
rule(-0.6, row(1, 3));
rule(-0.3, row(2, 2));
rule(0.0, row(2, 4), row(3,3), row(4, 2));
rule(0.3, row(4, 4));
rule(0.6, row(5, 3));
}}.build();
Second shot
In order to elimate the final "build()" call and double brace init you could try with:
class RuleBuilder2 extends HashMap<Double, Integer[][]> {
public RuleBuilder2 rule(double key, Integer[]... rows) {
put(key, rows);
return this;
}
public Integer[] row(Integer... ints) {
return ints;
}
}
in this case the code is a little better:
private static final Map<Double, Integer[][]> rules2 =
new RuleBuilder2().
rule(-0.6, row(1, 3)).
rule(-0.3, row(2, 2)).
rule(0.0, row(2, 4), row(3,3), row(4, 2)).
rule(0.3, row(4, 4)).
rule(0.6, row(5, 3));
EDIT
Probably the names that I've used are not so meaningful; boxed/unboxed conversion is still a problem but this is a problem of Java
Related
This is the follow up of compare sets
I have
Set<Set<Node>> NestedSet = new HashSet<Set<Node>>();
[[Node[0], Node[1], Node[2]], [Node[0], Node[2], Node[6]], [Node[3], Node[4], Node[5]] [Node[2], Node[6], Node[7]] ]
I want to merge the sets when there are two elements in common. For example 0,1,2 and 0,2,6 has two elements in common so merging them to form [0,1,2,6].
Again [0,1,2,6] and [2,6,7] has 2 and 6 common. so merging them and getting [0,1,2,6,7].
The final output should be :
[ [Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]] ]
I tried like this :
for (Set<Node> s1 : NestedSet ) {
Optional<Set<Node>> findFirst = result.stream().filter(p -> { HashSet<Node> temp = new HashSet<>(s1);
temp.retainAll(p);
return temp.size() == 2; }).findFirst();
if (findFirst.isPresent()){
findFirst.get().addAll(s1);
}
else {
result.add(s1);
}
}
But the result I got was :
[[Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]], [Node[0], Node[2], Node[6], Node[7]]]
Any idea ? Is there any way to get the desired output?
Some considerations:
Each time you apply a merge, you have to restart the procedure and iterate over the modified collection. Because of this, the iteration order of the input set is important, if you want your code to be deterministic you may want to use collections that give guarantees over their iteration order (e.g. use LinkedHashSet (not HashSet) or List.
Your current code has side effects as it modifies the supplied sets when merging. In general I think it helps to abstain from creating side effects whenever possible.
The following code does what you want:
static <T> List<Set<T>> mergeSets(Collection<? extends Set<T>> unmergedSets) {
final List<Set<T>> mergedSets = new ArrayList<>(unmergedSets);
List<Integer> mergeCandidate = Collections.emptyList();
do {
mergeCandidate = findMergeCandidate(mergedSets);
// apply the merge
if (!mergeCandidate.isEmpty()) {
// gather the sets to merge
final Set<T> mergedSet = Sets.union(
mergedSets.get(mergeCandidate.get(0)),
mergedSets.get(mergeCandidate.get(1)));
// removes both sets using their index, starts with the highest index
mergedSets.remove(mergeCandidate.get(0).intValue());
mergedSets.remove(mergeCandidate.get(1).intValue());
// add the mergedSet
mergedSets.add(mergedSet);
}
} while (!mergeCandidate.isEmpty());
return mergedSets;
}
// O(n^2/2)
static <T> List<Integer> findMergeCandidate(List<Set<T>> sets) {
for (int i = 0; i < sets.size(); i++) {
for (int j = i + 1; j < sets.size(); j++) {
if (Sets.intersection(sets.get(i), sets.get(j)).size() == 2) {
return Arrays.asList(j, i);
}
}
}
return Collections.emptyList();
}
For testing this method I created two helper methods:
static Set<Integer> set(int... ints) {
return new LinkedHashSet<>(Ints.asList(ints));
}
#SafeVarargs
static <T> Set<Set<T>> sets(Set<T>... sets) {
return new LinkedHashSet<>(Arrays.asList(sets));
}
These helper methods allow to write very readable tests, for example (using the numbers from the question):
public static void main(String[] args) {
// prints [[2, 6, 7, 0, 1]]
System.out.println(mergeSets(sets(set(0, 1, 2, 6), set(2, 6, 7))));
// prints [[3, 4, 5], [0, 2, 6, 1, 7]]
System.out.println(
mergeSets(sets(set(0, 1, 2), set(0, 2, 6), set(3, 4, 5), set(2, 6, 7))));
}
I'm not sure why you are getting that result, but I do see another problem with this code: It is order-dependent. For example, even if the code worked as intended, it would matter whether [Node[0], Node[1], Node[2]] is compared first to [Node[0], Node[2], Node[6]] or [Node[2], Node[6], Node[7]]. But Sets don't have a defined order, so the result is either non-deterministic or implementation-dependent, depending on how you look at it.
If you really want deterministic order-dependent operations here, you should be using List<Set<Node>>, rather than Set<Set<Node>>.
Here's a clean approach using recursion:
public static <T> Set<Set<T>> mergeIntersectingSets(Collection<? extends Set<T>> unmergedSets) {
boolean edited = false;
Set<Set<T>> mergedSets = new HashSet<>();
for (Set<T> subset1 : unmergedSets) {
boolean merged = false;
// if at least one element is contained in another subset, then merge the subsets
for (Set<T> subset2 : mergedSets) {
if (!Collections.disjoint(subset1, subset2)) {
subset2.addAll(subset1);
merged = true;
edited = true;
}
}
// otherwise, add the current subset as a new subset
if (!merged) mergedSets.add(subset1);
}
if (edited) return mergeIntersectingSets(mergedSets); // continue merging until we reach a fixpoint
else return mergedSets;
}
I try to implement a hashmap like HashMap<String,MyBigList>
But I can't form my MyBigList. The following is the exact HashMap i'm trying to create.
{word=[ [1, [0, 2] ], [ 2, [2]] ], word2=[ [ 1, [1] ] ]}
I want a big list of single lists like the following
[ [single list], [single list], .. ]
and the single list containing an int and a list of ints
[single list] = [1, [0,2]]
I tried using an ArrayList inside an ArrayList inside an ArrayList, but it didn't work.
I even tried creating a new class having as members an int, and a ArrayList<Integer>
but it didn't work either.
import java.util.ArrayList;
import java.util.HashMap;
public class NewClass {
int id;
ArrayList<Integer> posList;
public NewClass(){
this.id = 0;
this.posList = new ArrayList<Integer>();
}
public NewClass(int _id, int a, int b){
id = _id;
this.posList = new ArrayList<Integer>();
posList.add(a);
posList.add(b);
}
public String toString(){
return "" + this.id + " " + this.posList;
}
public static void main(String[] args) {
NewClass n = new NewClass(1,2,3);
HashMap<String,ArrayList<ArrayList<NewClass>>> map = new HashMap<String,ArrayList<ArrayList<NewClass>>>();
ArrayList<ArrayList<NewClass>> bigList = new ArrayList<ArrayList<NewClass>>();
ArrayList<NewClass> nList = new ArrayList<NewClass>();
nList.add(n);
nList.add(n);
bigList.add(nList);
map.put("word", bigList);
System.out.println(map);
}
}
produces
{word=[[1 [2, 3], 1 [2, 3]]]}
So a Map<String, List<Object>> with no type safety around the sublist (seeing as you have Integers and lists)?
That sounds overcomplicated to put it lightly. They don't have Collections so that you can nest them for all your data, if you really want to make data easy, use a class to represent it, and store that class in a Map using some aspect as a key to get to it:
public class MyClass {
private final String word;
public MyClass(String word) {
this.word = word;
}
// Other Data needed
public String getWord() { return this.word; }
}
//In another class
Map<String, MyClass> words = new HashMap<>();
About Varargs, can i repeat the arguments in a group?
For instance, i want to allow users pass in:
myFunc(1, "one");
myFunc(1, "one", 2, "two");
myFunc(1, "one", 2, "two", 3, "three");
It seems impossible. But as mentioned in the docs, the varargs is in fact an array, in old implementation. i would like to know how was people do before varargs is invented. That might inspire us how to achieve the above scenario. We can regard my scenario as {int, String}... repeating afterall.
Thanks for any input :-)
Edit:
Thanks for all your inputs!
So, is it calling by myFunc(new wrap(1, "one"), new wrap(2, "two"), new wrap(3, "three")); is the old method?
Edit 2:
Well, nope. Thats my fault of confusion.
For
myFunc(1);
myFunc(1, 2);
myFunc(1, 2, 3);
the old way should be
myFunc(new int[]{1});
myFunc(new int[]{1, 2});
myFunc(new int[]{1, 2, 3});
As far as i can see, as the repeating arguments form an array. All its arguments has to be of the same type. It should be impossible to achieve the above calls in a simple way. For curiosity, i start thinking of the possibility of operator overloading ... (?)
In this case, it seems to me that it's suitable to create a datastructure for your "pair", and then use that type as vararg argument to your method.
public void myFunc(Pair... pairs) {}
You could also use Object..., but I don't see any advantages in this case, since the arguments always come in pairs.
There are good reasons to use the other solutions, but they all introduce a bit of clutter (to create all those objects) you might not want to subject the users of your library to.
You can shift the clutter to the inside of your method like so:
public void example(final Object... args) {
if (args.length % 2 != 0)
throw new IllegalArgumentException("int, String pairs are required, but there seems to be an odd one out");
for (int i = 0; i < args.length; i += 2) {
int a = (Integer) args[i];
String b = (String) args[i + 1];
System.out.printf("%d: %s\n", a, b);
}
}
example(1, "Hello", 2, "Goodbye", 25, "Raptors will eat you!"); will then produce the following output:
1: Hello
2: Goodbye
25: Raptors will eat you!
Var args were introduced to allow you to send an arbitrary number of arguments to a function. Folks hacked around with other Collections / arrays before they came about.
You can achieve what you want with a custom structure. The particulars of the structure will depend on what the name value pair should achieve. Here is a generic solution for any NameValue pair.
NameValuePair
class NameValuePair<K,V>
{
private K key;
private V value;
public K getKey()
{
return key;
}
public void setKey(K key)
{
this.key = key;
}
public V getValue()
{
return value;
}
public void setValue(V value)
{
this.value = value;
}
}
Usage
private <K,V> void method(NameValuePair<K, V>... pairs )
{
for (NameValuePair<K, V> nameValuePair : pairs)
{
K key = nameValuePair.getKey();
V value = nameValuePair.getValue();
// logic goes here
}
}
What about creating a wrapper class that wraps the two parameters together?
public class TwoParameter
{
private int intValue;
private String stringValue;
public TwoParameter(int intValue, String stringValue)
{
this.intValue = intValue;
this.stringValue = stringValue;
}
// getters and setters
}
and then use it like:
myFunc(new TwoParameter(1, "one"), new TwoParameter(2, "two"));
The signature of the method would be something like this:
public void myFunc(TwoParameter... params){...}
I have to find a best way to find out that elements which is not presented in the second arraylist.
suppose
Arraylist a,b,
Arraylist a={1,2,3,4,5};
Arraylist b={2,3,4};
So basically what I want is to find out that elements of a which is not present in arraylist b.
So what is the best solutions to do that?
List<Integer> c = new ArrayList<>(a);
c.removeAll(b);
Also consider to use Sets instead of Lists.
here is another approach using java 8 -
a.stream().filter(b::contains).collect(Collectors.toList());
You could use Apache Commons Collections, which has a method explicitly for this purpose:
public static void main(String[] args) {
List<Integer> a = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
List<Integer> b = Arrays.asList(new Integer[] { 2, 3, 4 });
Collection<Integer> aMinusB = CollectionUtils.subtract(a, b);
System.out.println(aMinusB);
}
The printed result is: [1, 5].
The Apache Commons libs are well tested and commonly used to extend standard Java functionalities. This particular method accepts Iterable as parameters, so you can use any Collection you want. You can also mix different collection types:
public static void main(String[] args) {
List<Integer> a = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
Set<Integer> b = new HashSet<Integer>(Arrays.asList(new Integer[] { 2, 3, 4 }));
Collection<Integer> aMinusB = CollectionUtils.subtract(a, b);
System.out.println(aMinusB);
}
The printed result is the same, [1, 5].
Check out the Javadoc here.
For sake of completeness, Google's Guava library does not have this feature:
Collection *subtract*(Collection, Collection)
No equivalent--create an ArrayList containing a and then call remove on it for each element in b.
However, it implements a method called Sets.difference() method, which you could use if you prefer Guava and work with sets:
public static void main(String[] args) {
Set<Integer> a = new HashSet<Integer>(Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 }));
Set<Integer> b = new HashSet<Integer>(Arrays.asList(new Integer[] { 2, 3, 4 }));
Set<Integer> aMinusB = Sets.difference(a, b);
System.out.println(aMinusB);
}
The result is all elements in a that doesn't exist in b (i.e. [1, 5] again). Of course, the order is not determined since it operates on sets.
You can try removeAll:
List<Integer> notPresent = new ArrayList<Integer>(a);
notPresent.removeAll(b);
Use org.apache.commons.collections4.ListUtils
Given
List<Integer> a = Arrays.asList(new Integer[]{ 1,2,3,4,5});
List<Integer> b = Arrays.asList(new Integer[]{0,1,2,3});
Action
List<Integer> c = ListUtils.removeAll(b, a)
Result in List c
4, 5
Please try like this
for (Object o : a) {
if (!b.contains(o)) {
// this is not present
}
}
Loop through one list, then check if each element in other list using contains.
Something like this. If you think there may be duplicates in a you can try another type of Collection, like a Set for notPresent.
List<Integer> notPresent = new ArrayList<Integer>();
for (Integer n : a){
if (!b.contains(n)){
notPresent.add(n);
}
}
Try this:
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
List<Integer> b = new ArrayList<Integer>();
List<Integer> exclusion = new ArrayList<Integer>();
a.add(1);
a.add(2);
a.add(3);
a.add(4);
b.add(1);
b.add(2);
b.add(3);
b.add(5);
for (Integer x : a) {
if (!b.contains(x)) {
exclusion.add(x);
}
}
for (Integer x : exclusion) {
System.out.println(x);
}
}
Try this...
Use the contains() method of List.
ArrayList<Integer> aList = new ArrayList<Integer>();
for (Integer i : a){
if (!(b.contains(i))){
aList.add(i);
}
else{
continue;
}
}
Ok I am relatively new to Java Programming, but have previous experience in C++. I want to search an array for a specific item, but what if there are more than one of the same specific item? Would it be best to use a temporary array to store all found items in the array and return the temporary array?
Note: I'm trying to find the best way of doing this with memory management and speed. And it's not for Home work:)
Use apache commons lib, which solve a lot of issues. Use this if you want to filter by predicate and select sub array
CollectionUtils.filter(
Arrays.asList(new Integer[] {1,2,3,4,5}),
new Predicate() {
public boolean evaluate(final Object object) {
return ((Integer) object) > 2;
}
}
);
In case if you would like to select item(s) use
CollectionUtils.select(Collection inputCollection, Predicate predicate)
Use true java way - Navigable set and maps
NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive);
If you able to skip Java, then in Scala it will be much easier:
scala> val a = Array(4, 6, 8, 9, 4, 2, 4, 2)
a: Array[Int] = Array(4, 6, 8, 9, 4, 2, 4, 2)
scala> a.filter(_ == 4)
res0: Array[Int] = Array(4, 4, 4)
just use guava library as the simplest solution:
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html
or
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Collections2.html
Just use an ArrayList. Example:
/** Returns all strings starting with the letter a.*/
public static List<String> getStartsWithA(String[] strs) {
List<String> ret = new ArrayList<String>();
for (String s: strs) {
if (s.startsWith("a") || s.startsWith("A")) {
ret.add(s);
}
}
return ret;
}
ArrayList's internal array will dynamically grow as more space is needed.
I would use a "ready to use" implementation like a HashMap. You say "search", so I believe that you have a searchkey (in my proposal the String) under wich you can store your data (for example an Integer).
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
void storeValue(final String key, final Integer value) {
List<Integer> l = this.map.get(key);
if (l == null) {
synchronized (this.map) {
if (l == null) {
l = new Vector<Integer>();
this.map.put(key, l);
}
}
}
l.add(value);
}
List<Integer> searchByKey(final String key) {
return this.map.get(key);
}
With this, you can store multiple Integers # one key. Of course you can store other Object than the Integers.