I realise that this question may have been asked many times before,
but for this particular application using loops won't really work because I can't index into a set
What I'm looking to do is getting a set of possible unordered pairs from data in a hashset as efficiently as possible.
So if my hashset contained A, B, C, D , E
Then the following combinations are possbile: AB, AC, AD, AE, BC, BD, BE, CD, CE, DE
What options do I have available to achieve this efficiently?
Any ideas would be greatly appreciated
As far as the efficiency goes, there aren't too many options out there: you need to produce a set of N2 items, meaning that the timing would also be at least of the same order.
Since enumerating a set is linear, two nested loops will deal with this as efficiently as any other method would.
The loop on the outside should iterate the collection from the beginning. The loop on the inside should start at the position of the outer loop's iterator, incremented by one position.
You can still index your data, just add an additional HashMap<Your_Class, Integer> map to store the index of a particular data.
HashSet<Your_Class> set = ...//HashSet that contains data
int index = 0;
HashMap<Your_Class,Integer> map = new HashMap<>();
for(Your_Class item : set){
map.put(item, index++);
}
//Generate all the set with those indexes, and replace them with map.get(index)
So, in the example case, A has index 0, B has index 1,...., So for each pair 01, 02, 03..., just need to convert it back into AB, AC ,...
There aren't too may options. You can arrange your objects in an imutable object Class with the two objects like this:
public T Class Arrangement<T>{
private final T object1;
private final T object2;
public Arrangement(T object1, T)
// get methods...
}
Set<MyType> mySet = new HashSet<MyType>();
mySet.add(new Arrangement(myObject1, myObject2);
Something like this!
Related
I need to solve two problems for our project, where (1) I have to find a way in which I can keep an array (String[] or int[]) as a key of the Map. The requirement is that, if the contents of two arrays are equal (String[] a={"A","B"}, String[] b={"B","A"}) then they should be considered as equal/same keys, i.e., if I use a, or b as key of Map then a.equal(b)=true
I found that Java Sets adds the hashcodes of all the objects stored in them. The addition of hashcode allows to compare two hashsets, to see if they are equal or not, this means that such mechanism allows to compare two java Sets based on their contents.
So for the above problem I can use Sets as a Key of the Map, but the thing is I want to use Arrays as Key. So any idea for this?
(2) the next thing is, we are interested in an efficient partial key matching mechanism. For instance, to see if any key in the Map contains a portion of the Array, such as to find some thing like Key.contains(new String[]{"A"}).
Please share your ideas, any alternate way of doing this, I am concern with space and time optimal implementations. As this will be used in Data Stream processing projects. So space and time is really an issue.
Q1 - You can't use bare arrays as HashMap keys if you want key equality based on the array elements. Arrays inherit equals(Object) and hashCode() implementations from java.lang.Object, and they are based on object identity, not array contents.
The best alternative I can think of is to wrap the arrays as (immutable) lists.
Q2 - I don't think there is a simple efficient way to do this. The best I can think of are:
Extract all possible subarrays of each array and make each one an alternative key in the hash table. The problem is that the keys will take O(N M^2) space where M is the average (?) number of strings in the primary key String[]'s . Lookup will still be O(1).
Build an inverted index that gives the location of each string in all of the keys, then do a "phrase search" for a sequence of strings in the key space. That should scale better in terms of space usage, but lookup is a lot more expensive. And it is complicated.
I try to use lambda expression in Java8 to solve your problem
For Problem 1:
String[] arr1 = {"A","B","A","C","D"};
List<String> list1 = new ArrayList<String>(new LinkedHashSet<>(Arrays.asList(arr1)));
list1.stream().forEach(x -> System.out.println(x));
If you would like to compare them if they are equal. I suggest you could sort them first and then compare.
Of course, It's much better to use Set and Hashcode to do comparsion
For Problem 2(Some variable in the above would be re-used):
String[] arr2 = {"A"};
List<String> list2 = new ArrayList<String>(Arrays.asList(arr2)); //Assume List2 element is also unique
int NumOfKeyContain = list1.stream().filter(a -> (list2.stream().filter(b -> !b.equals(a)).count())<list2.size())
.collect(Collectors.toList())
.size();
System.out.println(NumOfKeyContain); //NumOfKeyContain is the number that of key in list2 contained by list1
I'm using Set to isolate the unique values of a List (in this case, I'm getting a set of points):
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
This will return a set of unique points, but for every item in listToCull, I'd like to test the following: if there is a duplicate, cull all of the duplicate items. In other words, I want pointSet to represent the set of items in listToCull which are already unique (every item in pointSet had no duplicate in listToCull). Any ideas on how to implement?
EDIT - I think my first question needs more clarification. Below is some code which will execute what I'm asking for, but I'd like to know if there is a faster way. Assuming listToCull is a list of PVectors with duplicates:
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
List<PVector> uniqueItemsInListToCull = new ArrayList<PVector>();
for(PVector pt : pointSet){
int counter=0;
for(PVector ptCheck : listToCull){
if(pt==ptCheck){
counter++;
}
}
if(counter<2){
uniqueItemsInListToCull.add(pt);
}
}
uniqueItemsInListToCull will be different from pointSet. I'd like to do this without loops if possible.
You will have to do some programming yourself: Create two empty sets; on will contain the unique elements, the other the duplicates. Then loop through the elements of listToCull. For each element, check whether it is in the duplicate set. If it is, ignore it. Otherwise, check if it is in the unique element set. If it is, remove it there and add to the duplicates set. Otherwise, add it to the unique elements set.
If your PVector class has a good hashCode() method, HashSets are quite efficient, so the performance of this will not be too bad.
Untested:
Set<PVector> uniques = new HashSet<>();
Set<PVector> duplicates = new HashSet<>();
for (PVector p : listToCull) {
if (!duplicates.contains(p)) {
if (uniques.contains(p)) {
uniques.remove(p);
duplicates.add(p);
}
else {
uniques.add(p);
}
}
}
Alternatively, you may use a third-party library which offers a Bag or MultiSet. This allows you to count how many occurrences of each element are in the collection, and then at the end discard all elements where the count is different than 1.
What you are looking for is the intersection:
Assuming that PVector (terrible name by the way) implements hashCode() and equals() correctly a Set will eliminate duplicates.
If you want a intersection of the List and an existing Set create a Set from the List then use Sets.intersection() from Guava to get the ones common to both sets.
public static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2)
Returns an unmodifiable view of the intersection of two sets. The returned set contains all
elements that are contained by both backing sets. The iteration order
of the returned set matches that of set1. Results are undefined if
set1 and set2 are sets based on different equivalence relations (as
HashSet, TreeSet, and the keySet of an IdentityHashMap all are).
Note: The returned view performs slightly better when set1 is the
smaller of the two sets. If you have reason to believe one of your
sets will generally be smaller than the other, pass it first.
Unfortunately, since this method sets the generic type of the returned
set based on the type of the first set passed, this could in rare
cases force you to make a cast, for example:
Set aFewBadObjects = ... Set manyBadStrings =
...
// impossible for a non-String to be in the intersection
SuppressWarnings("unchecked") Set badStrings = (Set)
Sets.intersection(
aFewBadObjects, manyBadStrings); This is unfortunate, but should come up only very rarely.
You can also do union, complement, difference and cartesianProduct as well as filtering very easily.
So you want pointSet to hold the items in listToCull which have no duplicates? Is that right?
I would be inclined to create a Map, then iterate twice over the list, the first time putting a value of zero in for each PVector, the second time adding one to the value for each PVector, so at the end you have a map with counts. Now you're interested in the keys of the map for which the value is exactly equal to one.
It's not perfectly efficient - you're operating on list items more times than absolutely necessary - but it's quite clean and simple.
OK, here's the solution I've come up with, I'm sure there are better ones out there but this one's working for me. Thanks to all who gave direction!
To get unique items, you can run a Set, where listToCull is a list of PVectors with duplicates:
List<PVector> culledList = new ArrayList<PVector>();
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
culledList.addAll(pointSet);
To go further, suppose you want a list where you've removed all items in listToCull which have a duplicate. You can iterate through the list and test whether it's in the set for each item. This let's us do one loop, rather than a nested loop:
Set<PVector> pointSet = new HashSet<PVector>(listToCull);
Set<PVector> removalList = new HashSet<PVector>();//list to remove
for (PVector pt : listToCull) {
if (pointSet.contains(pt)) {
removalList.add(pt);
}
else{
pointSet.add(pt);
}
}
pointSet.removeAll(removalList);
List<PVector> onlyUniquePts = new ArrayList<PVector>();
onlyUniquePts.addAll(pointSet);
Basically I have a method that takes a String name and will delete that entry if found.
I have a LinkedList composed of 26 LinkedList instances, named (alphabetically) as follows a, b, c, ..., z
Lets say when the user enters a word like "Charlie" so I want to delete it.
Charlie starts with 'c' so how can I make my code point to the LinkedList c without having to traverse all the LinkedList items.
So far I get the name Charlie, get char at 0 index, convert it to lowercase and call it String Letter. Is there a way to do [Letter].remove(name);
I asked a similar question but I don't think I wrote it well.
Thanks.
Maybe you should take a look closer into the java API and try not to reinvent the wheel. Basically you can use a HashMap to wrap you LinkedList instances instead of using a LinkedList because it will let you select your items based on a key (the alphabet characters in your case)
Map<Character,LinkedList> myMap = new HashMap<Character,LinkedList>();
After having filled your Map (simply calling myMap.put('c', new LinkedList()) and so on for each char), you can get the desired LinkedList, without having to iterate through the whole map:
myMap.get('c');
You are looking for a trie data structure.
If you still want to do it using your approach, Instead of having a linked list of lists, try having an array of arrays.Might come in handy
Imagine I have the following List of values:
List<String> values = Lists.asList("a", "a", "b", "c");
Now I want to add an index to all values, so that one ends up with this as list:
a1 a2 b1 c1 // imagine numbers as subscript
I want to use a FluentIterable and its transform method for that, so something like this:
from(values).transform(addIndexFunction);
The problem with that is, that addIndexFunction needs to know, how often the index was already increased - think of a2, when adding the index to this a, the function needs to know, that there was alraedy an a1.
So, is there some kind of best practice for doing such a thing? My current idea is to create a Map with each letter as key, so:
Map<String,Integer> counters = new HashMap<>();
// the following should be generated automatically, but for the sake of this example it's done manually...
counters.put("a", 0);
counters.put("b", 0);
counters.put("c", 0);
and then modify my transform call:
from(values).transform(addIndexFunction(counters));
As Map is an object and passed by reference, I can now share the counter state between the transformations, right? Feedback, better ideas? Is there some built-in mechanism for such things in Guava?
Thanks for any hint!
Use a Multiset to replace the HashMap, and you're good to go, following #Perception's suggestion to encapsulate the Multiset in the Function itself and aggregating data as the function is applied.
Don't use transform here, or your iterable will have different values every time you iterate over it, and will generally behave very weirdly. (It's also somewhat frowned upon to have state in a Function.)
Instead, do a proper for loop with a Multiset helper:
Multiset<String> counts = HashMultiset.create();
List<Subscript> result = Lists.newArrayList();
for (String value : values) {
int count = counts.add(value, 1);
result.add(new Subscript(value, count));
}
I have a question regarding the LinkedList class in Java.
I have a scenario wherein i need to add or set an index based on whether the index exists in the linkedlist or not. A pseudo-code of what i want to achieve is --
if index a exists within the linkedlist ll
ll.set(a,"arbit")
else
ll.add(a,"arbit")
I did go through the Javadocs for the LinkedList class but did not come across anything relevant.
Any ideas ?
Thanks
p1ng
What about using a Map for this:
Map<Integer, String> map = new HashMap<Integer, String>();
// ...
int a = 5;
map.put(a, "arbit");
Even if a already exists, put will just replace the old String.
Searching in linked list is not very efficient (O(n)). Have you considering using different data structure - e.g. HashMap which would give you O(1) access time?
If you need sequential access as well as keyed access you might want to try a LinkedHashMap, available as from 1.4.2
http://download.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html
Map<Integer, String> is definitely a good (the best?) way to go here.
Here's an option for keeping with LinkedList if that's for some bizarre reason a requirement. It has horrible runtime performance and disallows null, since null now becomes an indicator that an index isn't occupied.
String toInsert = "arbit";
int a = 5;
//grow the list to allow index a
while ( a >= ll.size() ) {
ll.add(null);
}
//set index a to the new value
ll.set(a, toInsert);
If you're going to take this gross road, you might be better off with an ArrayList.
Why is it so bad? Say you had only one element at index 100,000. This implementation would require 100,000 entries in the list pointing to null. This results in horrible runtime performance and memory usage.
LinkedList cannot have holes inside, so you can't have list [1,2,3,4] and then ll.add(10,10), so I think there's something wrong with your example. Use either Map or search for some other sparse array
It looks like you're trying to use a as a key, and don't state whether you have items at index i < a. If you run your code when ll.size() <= a then you'll end up with a NullPointerException.
And if you add an item at index a the previous item at a will now be at a+1.
In this case it would be best to remove item at a first (if it exists) then add item "arbit" into a. Of course, the condition above re: ll.size() <=a still applies here.
If the order of the results is important, a different approach could use a HashMap<Integer,String> to create your dataset, then extract the keys using HashMap<?,?>.getKeySet() then sort them in their natural order (they're numeric after all) then extract the values from the map while iterating over the keySet. Nasty, but does what you want... Or create your own OrderedMap class, that does the same...
Could you expand on why you need to use a LinkedList? Is ordering of the results important?