Resolving multiple values returned from a query? - java

While this seems like a really simple problem, the only solution I've come up with is below, any suggestions for something less ugly with lower time complexity?
My application is in Java and is retrieving with a MS-sql DB using skife.jdbi.
Say I have a Tablewith columns A, B, and C where A and B form a primary key. And I want to retrieve C given a particularly A and B. This is easily accomplished. But what if I my throughput requirement is very high, so I want to make these Select statements in batches. I end up with something like the below:
Given a Set of Objects with values A and B, I iterate the List compiling all the values of A and B. I then run a query like SELECT A, B, C FROM tbl WHERE A IN :listOfAs AND B IN :listOfBs. I then iterate the results of the query, matching a result to the original object by comparing the A and B value. Which all sounds reasonable, but the code ends up looking like the below, which seems ugly and suboptimal?
class MyObject {
String A;
String B;
String C;
Object otherData;
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof MyObject)) {
return false;
} else {
return A.equals(other.A) && B.equals(other.B);
}
}
#Override
public int hashCode() {
return 31 * A.hashCode() + B.hashCode();
}
}
// populates the of objects with their proper C value
void retrieveC(Set<MyObject> input) {
Set<String> aValues = new HashSet<>();
Set<String> bValues = new HashSet<>();
for (MyObject object : input) {
aValues.add(object.A);
bValues.add(object.B);
}
// the dao executes the query mentioned above, and returns a Set of
// MyObject instances with members A, B, and C populated from the results.
// Any results that do not contain a value for A, B, and C (which
// shouldn't exit) are filtered out by the dao.
Set<MyObject> results = dao.selectC(aValues, bValues);
// ewww... O(n^2)
for (MyObject object : input) {
boolean resultFound = false;
for (MyObject result : results) {
if (object.equals(result)) {
object.C = result.C;
resultFound = true;
break;
}
}
if (!resultFound) {
// handle this case
}
}
}

I take it that ideal would be
SELECT A, B, C FROM tbl WHERE A+' '+B IN :listOfAandBs
That is not listOfAs x listOfBs (quadratic complexity) but listofAs . listOfBs (linear, in-product)

Instead of the DAO pattern you could turn to the fluent queries of JDBI.
This way you could switch batching to streaming. In the example given at the JDBI page you would exchange the StringBuilder() with something that allows you to stream your results to your receiver one by one as the database returns them.
If this is possible depends of course on your development environment.

Related

what is proper java collection with unique element (like set) with get element feature

I Used Java HashSet for storing unique elements but now I want to retrieve element but HashSet does not has something like that, Here is what I want for my problem:
for my usecase LinkInfo hashCode() and equals() methods do not use LinkInfo.id field I want to get linkinfo instance from set and update all of its' fields except id field that should be from old instance
Set<LinkInfo> fooSet = new HashSet<>()
public void updateFoo(LinkInfo linkInfo) {
LinkInfo temp = fooSet.get(linkInfo);
linkInfo.setId(temp.getId());
// now update set
fooSet.remove(linkInfo)
fooSet.add(linkInfo)
}
Rather than
LinkInfo temp = fooSet.get(linkInfo);
the below logic is the same as what you seem to want
if (fooSet.contains(linkInfo)) {
temp = linkInfo;
}
I don't know why you're doing this, but to answer the question, yes you can do this, but you should use a map, like so:
import java.util.HashMap;
import java.util.Map;
public class Main {
static class Test {
public int a,b;
public Test(int a, int b) {
this.a = a;
this.b = b;
}
#Override
public boolean equals(Object obj) {
Test that = (Test)obj;
return this.a == that.a && this.b == that.b;
}
#Override
public int hashCode() {
return a ^ b;
}
}
public static void main(String[] args) {
Map<Test,Test> map = new HashMap<>();
Test t = new Test(1,2);
System.out.println(System.identityHashCode(t));
map.put(t, t);
Test t2 = new Test(1,2);
System.out.println(System.identityHashCode(t2));
System.out.println(System.identityHashCode(map.get(t2)));
}
}
Now you are able to retrieve the instance that you put into that map initially through an instance that is equal to it.
The program printed:
475266352
1355531311
475266352
on my computer. You can use a HashSet and iterate through it achieving the same result, but it won't be O(1).
You have a bit of a logical problem here. Why should an API that depends on equals() provide a method getElementEqualTo(e)? In order to use such a method, you need to present an object that, for the API's purposes, is equivalent to the desired result. What would be the point of that?
But that doesn't mean you're out of luck. I think you're saying that your LinkInfo class provides hashCode() and equals() methods suitable for identifying the object you want by means of a different object that you can obtain. In that case, it sounds like a HashMap could serve your purpose. Just map each key to itself.
HashMap<LinkInfo, LinkInfo> infos;
public void updateInfo(LinkInfo linkInfo) {
LinkInfo temp = infos.remove(linkInfo);
if (temp != null) {
linkInfo.setId(temp.getId());
}
infos.put(linkInfo, linkInfo);
}
I do agree with Scary answer above, but in case you want the exact reference that is stored in the Set instead of an similar equal object, you may use below code:
public void updateFoo(LinkInfo linkInfo) {
LinkInfo temp = null;
for(LinkInfo curLinkInfo:fooSet) if (curLinkInfo.equals(linkInfo))temp = curLinkInfo;
if(temp!=null)
linkInfo.setId(temp.getId());
// now update set
fooSet.remove(linkInfo)
fooSet.add(linkInfo)
}

Swap 2 values in 2 different AtomicReferences

I tried to implement a swap method for 2 AtomicReferences.
public void swap(AtomicReference<Object> a, AtomicReference<Object> b) {
while (true) {
Object value1 = a.get();
Object value2 = b.get();
if (a.compareAndSet(value1, value2) && b.compareAndSet(value2, value1)) return;
}
}
In my opinion, this solution is not correct. If multiple threads use this method at the same time, it could lead to the following scenario:
T1: ...get(); get(); compareAndSet() == true //-> BREAK (scheduler)
T2: ...get(); get(); compareAndSet() == true; compareAndSet() == true; return;
This would mean, T1 had set the value of a but will fail by setting the value of b. T1 would repeat the process EVEN if AtomicReference a has been set.
Does someone of you have a better idea, how to implement something like this? It would be easy, if you would just have one AtomicReference. Maybe it isn't possible using 2 AtomicReference's and I should consider using one AtomicReference that points to an Object[].
In Scala, this method is super easy to implement, since you have atomic blocks.
class Swappy[A](_a: A, _b: A) {
#volatile
var a = Ref(_a)
#volatile
var b = Ref(_b)
def swap(): Unit = {
atomic {
implicit tx =>
val tmp = a
a = b
b = tmp
}
}
def elems: (A, A) = (a.single(), b.single())
}
I created a solution with a different approach. This should be 100% thread safe. I switched to using just one AtomicReference. If anyone could find a better way, feel free to write an answer. :)
package test;
import java.util.concurrent.atomic.*;
public class ScalaSTMPendant {
AtomicReference<Object[]> a;
public ScalaSTMPendant(Object a, Object b) {
this.a = new AtomicReference<>(new Object[] {a,b});
}
public void swap() {
while (true) {
Object[] origin = a.get();
Object[] swapped = new Object[] {origin[1], origin[0]};
if (a.compareAndSet(origin, swapped)) return;
}
}
public Object[] elems() {
Object[] temp = a.get();
return new Object[] {temp[0], temp[1]};
}
}
Would an Exchanger help? I'm not sure who is swapping what, but an Exchanger would help you do a swap atomically.
Also, the scala sample above uses ScalaSTM. You could do the same in Java using another STM implementation (or even ScalaSTM). For example: Multiverse.

Is there a way to create an AND/OR/ETC. Boolean statement that is comparing with the same value without redefining the value? [duplicate]

This question already has answers here:
Best way to format multiple 'or' conditions in an if statement
(8 answers)
Closed 1 year ago.
Basically, what I want to do is check two integers against a given value, therefore, classically what you would do is something like this:
//just to get some values to check
int a, b;
a = (int)(Math.random()*5);
b = (int)(Math.random()*5);
//the actual thing in question
if(a == 0 || b == 0)
{
//Then do something
}
But is there a more concise format to do this? Possibly similar to this (which returns a bad operand type):
//just to get some values to check
int a, b;
a = (int)(Math.random()*5);
b = (int)(Math.random()*5);
//the actual thing in question
if((a||b) == 0)
{
//Then do something
}
You can do the following in plain java
Arrays.asList(a, b, c, d).contains(x);
Unfortunately there is no such construct in Java.
It this kind of comparison is frequent in your code, you can implement a small function that will perform the check for you:
public boolean oneOfEquals(int a, int b, int expected) {
return (a == expected) || (b == expected);
}
Then you could use it like this:
if(oneOfEquals(a, b, 0)) {
// ...
}
If you don't want to restrict yourselft to integers, you can make the above function generic:
public <T> boolean oneOfEquals(T a, T b, T expected) {
return a.equals(expected) || b.equals(expected);
}
Note that in this case Java runtime will perform automatic boxing and unboxing for primitive types (like int), which is a performance loss.
As referenced from this answer:
In Java 8+, you might use a Stream and anyMatch. Something like
if (Stream.of(b, c, d).anyMatch(x -> x.equals(a))) {
// ... do something ...
}
Note that this has the chance of running slower than the other if checks, due to the overhead of wrapping these elements into a stream to begin with.
I think that a bit-wise OR:
if ((a | b) == 0) . . .
would work if you want to check specifically for 0. I'm not sure if this saves any execution time. More to the point, it makes for cryptic code, which will make the future maintainer of this code curse you (even if its yourself). I recommend sticking with the more-typing option.
Bah. I misread OP's original logic.
Another go...
If you want to test whether any one of many variables is equal to an expected value, a generic function might work:
public <T> boolean exists(T target, T... values) {
for (T value : values) {
if (target == null) {
if (value == null) {
return true;
}
} else if (target.equals(value)) {
return true;
}
}
return false;
}
This will work for any number of objects of one type. Primitives will be autoboxed so it will work with them as well. Your original code will be something like:
if (test(0, a, b)) {
// do something
}
(A better method name would be desperately needed to even consider whether this an improvement over what you have now. Even if the test expands to 3 or 4 variables, I question the need for this kind of thing.) Note that this also works with arrays:
int[] values = { . . . };
if (test(0, values)) { . . .
and it can be used to test whether an array (or any of a collection of variables) is null.
if(a == 0 || b == 0)
{
//Then do something
}
Why not keep it readable? What is not concise about this? On the other hand,
a = (int)(Math.random()*5);
involves an unnecessary cast. Why not just use Random and invoke nextInt()?
For this example, you can do
if (a * b == 0)
or for more variables
if (a * b * c * d == 0)
while more concise it may not be as clear. For larger values, you need to cast to a long to avoid an overflow.
You could put the integers in a set and see if it contains the given value. Using Guava:
if(newHashSet(a, b).contains(0)){
// do something
}
But two simple int comparisons are probably easier to understand in this case.
Here's a modification of #buc's answer that can take any number of any arguments:
public <T> boolean oneOfEquals(T expected, T... os) {
for (T o : os) {
if (expected.equals(o)) return true;
}
return false;
}
Even if you have used the bit-wise operation as Ted suggested, the expressions are not equal, since one requires at least one of the variables to be zero and the second requires both of them to be zero.
Regarding your question, there is no such shortcut in Java.
You can try this code:
public static boolean match (Object ref, Object... objects)
{
if (ref == null)
return false;
//
for (Object obj : objects)
if (obj.equals (ref))
return true;
//
return false;
} // match
So if you can check this way:
if (match (reference, "123", "124", "125"))
; // do something
In Java 8 we can achieve the same by using the below method:
private boolean methodName(int variant,int... args){
if(args.length > 0){ return Arrays.stream(args).anyMatch( x -> x == variant); }
return false;
}
The given method will return true if the variant will match any possible input(s). This is used for or condition.
In the same way, if you want to do &&(and) condition then you just need to used other Java 8 methods:
Note: These methods take Predicate as an argument.
anyMatch: return true the moment the first predicate returns true otherwise false.
allMatch: return true if all the predicates return true otherwise false.
noneMatch: return true if none of the predicates return true otherwise false.
Performance Note: This is good when you have enough amount of data to
check as it has some overhead but it works really well when you use
this for enough amount of data. normal way is good for just two
conditions.
There is no special syntax for that. You could make a function for that. Assuming at least Java 1.5:
public <T> boolean eitherOneEquals(T o1, T o2, T expectedValue) {
return o1.equals(expectedValue) || o2.equals(expectedValue);
}
if(eitherOneEquals(o1, o2, expectedValue)) {
// do something...
}

Bidirectional multimap equivalent data structure

I know that Guava has a BiMultimap class internally but didn't outsource the code. I need a data structure which is bi-directional, i.e. lookup by key and by value and also accepts duplicates.
i.e. something like this: (in my case, values are unique, but two values can point to the same key)
0 <-> 5
1 <-> 10
2 <-> 7
2 <-> 8
3 <-> 11
I want to be able to get(7) -> returning 2 and get(2) returning [7, 8].
Is there another library out there which has a data structure I can make use of?
If not, what do you suggest is the better option to handle this case? Is keeping two Multimaps in memory one with and the other with a bad practice?
P.S.: I have read this question: Bidirectional multi-valued map in Java but considering it is dated in 2011, I thought I'll open a more recent question
What do you mean by
Guava has a BiMultimap class internally but didn't outsource the code
The code of an implementation is here.
I didn't check if this is a working implementation, nor if it made it into a release or if I'm just looking at some kind of snapshot. Everything is out in the open, so you should be able to get it.
From a quick glance at the source code it looks like the implementation does maintain two MultMaps, and this should be fine for the general case.
If you don't need the whole bunch of Guava HashBiMultimap functionality, but just getByKey() and getByValue(), as you specified, I can suggest the approach, where only one HashMultiMap is used as a storage.
The idea is to treat provided key and value as equilibrium objects and put both of them in the storage map as keys and values.
For example: Let we have the following multiMap.put(0, 5), so we should get the storage map containing something like this [[key:0, value:5], [key:5, value:0]].
As far as we need our BiMultiMap to be generic, we also need to provide some wrapper classes, that should be used as storage map type parameters.
Here is this wrapper class:
public class ObjectHolder {
public static ObjectHolder newLeftHolder(Object object) {
return new ObjectHolder(object, false);
}
public static ObjectHolder newRightHolder(Object object) {
return new ObjectHolder(object, true);
}
private Object object;
private boolean flag;
private ObjectHolder(Object object, boolean flag) {
this.object = object;
this.flag = flag;
}
public Object getObject() {
return object;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ObjectHolder)) return false;
ObjectHolder that = (ObjectHolder) o;
if (flag != that.flag) return false;
if (!object.equals(that.object)) return false;
return true;
}
#Override
public int hashCode() {
int result = object.hashCode();
result = 31 * result + (flag ? 1 : 0);
return result;
}
}
And here is the MultiMap:
public class BiHashMultiMap<L, R> {
private Map<ObjectHolder, Set<ObjectHolder>> storage;
public SimpleBiMultiMap() {
storage = new HashMap<ObjectHolder, Set<ObjectHolder>>();
}
public void put(L left, R right) {
ObjectHolder leftObjectHolder = ObjectHolder.newLeftHolder(left);
ObjectHolder rightObjectHolder = ObjectHolder.newRightHolder(right);
put(leftObjectHolder, rightObjectHolder);
put(rightObjectHolder, leftObjectHolder);
}
private void put(ObjectHolder key, ObjectHolder value) {
if (!storage.containsKey(key)) {
storage.put(key, new HashSet<ObjectHolder>());
}
storage.get(key).add(value);
}
public Set<R> getRight(L left) {
return this.get(ObjectHolder.newLeftHolder(left));
}
public Set<L> getLeft(R right) {
return this.get(ObjectHolder.newRightHolder(right));
}
private <V> Set<V> get(ObjectHolder key) {
Set<ObjectHolder> values = storage.get(key);
if (values == null || values.isEmpty()) {
return null;
}
Set<V> result = new HashSet<V>();
for (ObjectHolder value : values) {
result.add((V)value.getObject());
}
return result;
}
}
Thing that could seem strange is the left and right prefixed variable everywhere. You can think of them as left is the original key, that was putted to map and right is the value.
Usage example:
BiHashMultiMap<Integer, Integer> multiMap = new BiHashMultiMap<Integer, Integer>();
multiMap.put(0,5);
multiMap.put(1,10);
multiMap.put(2,7);
multiMap.put(3,7);
multiMap.put(2,8);
multiMap.put(3,11);
Set<Integer> left10 = multiMap.getLeft(10); // [1]
Set<Integer> left7 = multiMap.getLeft(7); // [2, 3]
Set<Integer> right0 = multiMap.getRight(0); // [5]
Set<Integer> right3 = multiMap.getRight(3); // [7, 11]
So to get left value we need to provide right value as key and to get right value we need to provide left as a key.
And of course to make map fully function we need to provide other methods, like remove(), contains() and so on.

Get specific objects from ArrayList when objects were added anonymously?

I have created a short example of my problem. I'm creating a list of objects anonymously and adding them to an ArrayList. Once items are in the ArrayList I later come back and add more information to each object within the list. Is there a way to extract a specific object from the list if you do not know its index?
I know only the Object's 'name' but you cannot do a list.get(ObjectName) or anything. What is the recommended way to handle this? I'd rather not have to iterate through the entire list every time I want to retrieve one specific object.
public class TestCode{
public static void main (String args []) {
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.add(new Party("FirstParty")); // all anonymously added
cave.parties.add(new Party("SecondParty"));
cave.parties.add(new Party("ThirdParty"));
// How do I go about setting the 'index' value of SecondParty for example?
}
}
class Cave {
ArrayList<Party> parties = new ArrayList<Party>();
}
class Party extends CaveElement{
int index;
public Party(String n){
name = n;
}
// getter and setter methods
public String toString () {
return name;
}
}
class CaveElement {
String name = "";
int index = 0;
public String toString () {
return name + "" + index;
}
}
Given the use of List, there's no way to "lookup" a value without iterating through it...
For example...
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.add(new Party("FirstParty")); // all anonymously added
cave.parties.add(new Party("SecondParty"));
cave.parties.add(new Party("ThirdParty"));
for (Party p : cave.parties) {
if (p.name.equals("SecondParty") {
p.index = ...;
break;
}
}
Now, this will take time. If the element you are looking for is at the end of the list, you will have to iterate to the end of the list before you find a match.
It might be better to use a Map of some kind...
So, if we update Cave to look like...
class Cave {
Map<String, Party> parties = new HashMap<String, Party>(25);
}
We could do something like...
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.put("FirstParty", new Party("FirstParty")); // all anonymously added
cave.parties.put("SecondParty", new Party("SecondParty"));
cave.parties.put("ThirdParty", new Party("ThirdParty"));
if (cave.parties.containsKey("SecondParty")) {
cave.parties.get("SecondParty").index = ...
}
Instead...
Ultimately, this will all depend on what it is you want to achieve...
List.indexOf() will give you what you want, provided you know precisely what you're after, and provided that the equals() method for Party is well-defined.
Party searchCandidate = new Party("FirstParty");
int index = cave.parties.indexOf(searchCandidate);
This is where it gets interesting - subclasses shouldn't be examining the private properties of their parents, so we'll define equals() in the superclass.
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CaveElement)) {
return false;
}
CaveElement that = (CaveElement) o;
if (index != that.index) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
return true;
}
It's also wise to override hashCode if you override equals - the general contract for hashCode mandates that, if x.equals(y), then x.hashCode() == y.hashCode().
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + index;
return result;
}
If you want to lookup objects based on their String name, this is a textbook case for a Map, say a HashMap. You could use a LinkedHashMap and convert it to a List or Array later (Chris has covered this nicely in the comments below).
LinkedHashMap because it lets you access the elements in the order you insert them if you want to do so. Otherwise HashMap or TreeMap will do.
You could get this to work with List as the others are suggesting, but that feels Hacky to me.. and this will be cleaner both in short and long run.
If you MUST use a list for the object, you could still store a Map of the object name to the index in the array. This is a bit uglier, but you get almost the same performance as a plain Map.
You could use list.indexOf(Object) bug in all honesty what you're describing sounds like you'd be better off using a Map.
Try this:
Map<String, Object> mapOfObjects = new HashMap<String, Object>();
mapOfObjects.put("objectName", object);
Then later when you want to retrieve the object, use
mapOfObjects.get("objectName");
Assuming you do know the object's name as you stated, this will be both cleaner and will have faster performance besides, particularly if the map contains large numbers of objects.
If you need the objects in the Map to stay in order, you can use
Map<String, Object> mapOfObjects = new LinkedHashMap<String, Object>();
instead
As per your question requirement , I would like to suggest that Map will solve your problem very efficient and without any hassle.
In Map you can give the name as key and your original object as value.
Map<String,Cave> myMap=new HashMap<String,Cave>();
I would suggest overriding the equals(Object) of your Party class. It might look something like this:
public boolean equals(Object o){
if(o == null)
return false;
if(o instanceof String)
return name.equalsIgnoreCase((String)o);
else if(o instanceof Party)
return equals(((Party)o).name);
return false;
}
After you do that, you could use the indexOf(Object) method to retrieve the index of the party specified by its name, as shown below:
int index = cave.parties.indexOf("SecondParty");
Would return the index of the Party with the name SecondParty.
Note: This only works because you are overriding the equals(Object) method.
You could simply create a method to get the object by it's name.
public Party getPartyByName(String name) {
for(Party party : parties) {
if(name.equalsIgnoreCase(party.name)) {
return party;
}
}
return null;
}

Categories

Resources