I have a HashSet of Strings in the format: something_something_name="value"
Set<String> name= new HashSet<String>();
Farther down in my code I want to check if a String "name" is included in the HashSet. In this little example, if I'm checking to see if "name" is a substring of any of the values in the HashSet, I'd like it to return true.
I know that .contains() won't work since that works using .equals(). Any suggestions on the best way to handle this would be great.
With your existing data structure, the only way is to iterate over all entries checking each one in turn.
If that's not good enough, you'll need a different data structure.
You can build a map (name -> strings) as follows:
Map<String, List<String>> name_2_keys = new HashMap<>();
for (String name : names) {
String[] parts = key.split("_");
List<String> keys = name_2_keys.get(parts[2]);
if (keys == null) {
keys = new ArrayList<>();
}
keys.add(name);
name_2_keys.put(parts[2], keys);
}
Then retrieve all the strings containing the name name:
List<String> keys = name_2_keys.get(name)
You can keep another map where name is the key and something_something_name is the value.
Thus, you would be able to move from name -> something_something_name -> value. If you want a single interface, you can write a wrapper class around these two maps, exposing the functionality you want.
I posted a MapFilter class here a while ago.
You could use it like:
MapFilter<String> something = new MapFilter<String>(yourMap, "something_");
MapFilter<String> something_something = new MapFilter<String>(something, "something_");
You will need to make your container into a Map first.
This would only be worthwhile doing if you look for the substrings many times.
Related
Please note that this is not a homework question. I am training on Kattis and I came by a question that requires the use of Union-Find paradigms. Given the nature of the problem, I decided to implement my own UnionFind data structure. I understand that the interface of my DS should support:
makeSet
find(elem) -> returns reference to the representative of that set
merge(firstElem, secondElem) -> merges the two parents of that set(also makes sure it is balanced)
Now the issue is I am not implementing this data structure to support Integers which is usually implemented using an array where the index is the value and the representative of the set is always the value at that index. Instead my set contains strings and I am finding difficulty in choosing the data structure.
if you have data like String [] universal_set = {"a,b,s","d,s,w","s,d,v","m,d,s"};,
create a HashMap and get unique values then group them as a disjoint sub set of the main set.
Here is a soultion for String-String union find, which may help.
//set all pairs
for(String[] pair : pairs){
String parent0 = find(pair[0], map);
String parent1 = find(pair[1], map);
if(!parent0.equals(parent1)) map.put(parent0, parent1);
}
//check if two string are same group
find(words1[i], map).equals(find(words2[i], map)
//find
private String find(String word, Map<String, String> map){
if(!map.containsKey(word)) return word;
String str = word;
while(map.containsKey(str)){
str = map.get(str);
}
map.put(word, str);
return str;
}
I am fairly new to Java and I have been trying to use TreeSets, all was well however, I want to split the values of a specific key to indiviual string. i.e.
Alice,3,1,6,3,6
would become:
Alice is a string
3 is a string
1 is a string
and then I would like to add them to an array so that:
Alice,3,1,6,3,6
Jon,5,3,1,6,5
Alice and Jon are in ArrayNames
3 and 5 are in ArrayScore1
I basically need the value to split into their values and then transferred to an array
All help is welcomed and appreciated
Thanks
Silver
It's a little hard to tell, but I think you actually want to create a Map<String, List<String>> from a Set<String>.
Try this:
Set<String> set = new TreeSet<>(); // doesn't matter what type of Set
// NOTE: You must populate the list somehow
Map<String, List<String>> map = new LinkedHashMap<>();
set.stream()
.map(s -> s.split(",")) // String to String[]
.<String[], List<String>>map(Arrays::asList) // convert String[] to List<String>
.forEach(a -> map.put(a -> a.get(0), a -> a.subList(1, a.size())));
Avoid using arrays unless you absolutely have to: Always prefer using Collections.
If you only want to do one thing with the data (ie you don't need to keep the map), instead of collecting the data, call .forEach() instead, for example:
...
.forEach(s -> System.out.println(s.get(0) + " has scores " + s.subList(1, s.size()));
Disclaimer: Code above may not compile or work as it was thumbed in on my phone (but there's a reasonable chance it will work)
Let's suppose I've an object that looks like this:
public class Supermarket {
public String supermarketId;
public String lastItemBoughtId;
// ...
}
and I have two lists of supermarkets, one "old", another "new" (i.e. one is local, the other is retrieved from the cloud).
List<Supermarket> local = getFromLocal();
List<Supermarket> cloud = getFromCloud();
I would like to find all the pairs of Supermarket objects (given supermarketId) that have lastItemBoughtId different from one another.
The first solution I have in mind is iterating the first List, then inside the first iteration iterating the second one, and each time that local.get(i).supermarketId.equals(cloud.get(j).supermarketId), checking if lastItemBoughtId of the i element is different from the id of the j element. If it's different, I add the whole Supermarket object on a new list.
To be clearer, something like this:
List<Supermarket> difference = new ArrayList<>();
for (Supermarket localSupermarket : local) {
for (Supermarket cloudSupermarket : cloud) {
if (localSupermarket.supermarketId.equals(cloudSupermarket.supermarketId) &&
!localSupermarket.lastItemBoughtId.equals(cloudSupermarket.lastItemBoughtId))
difference.add(cloudSupermarket);
}
}
Clearly this looks greatly inefficient. Is there a better way to handle such a situation?
One solution :
Construct a Map of the Local supermarkets using the supermarketId as the key by running through the list once
Loop through the cloud list and do you comparison, looking up the local supermarket from your map.
i.e. O(n) instead of O(n2)
Here's a two-line solution:
Map<String, Supermarket> map = getFromLocal().stream()
.collect(Collectors.toMap(s -> s.supermarketId, s -> s));
List<Supermarket> hasDiffLastItem = getFromCloud().stream()
.filter(s -> !map.get(s.supermarketId).lastItemBoughtId.equals(s.lastItemBoughtId))
.collect(Collectors.toList());
I would put one of the lists in a Map with as key the Supermarket ID and as value the supermarket instance then iterate over the other getting from the Map and comparing the lastItemBoughtId.
I have the following list:
List<ArrayList> list;
list.get(i) contains the ArrayList object with the following values {p_name=set1, number=777002}.
I have to create a
Map<key,value>
where the key contains the p_name, and values are the numbers.
How to do it easily and fast as there can be hundreds of entries in the initial list and each number can be present in multiple p_name entries.
Update: Here is my current solution
List<Row> list; //here is my data
Map<String,String> map = new TreeMap<String,String>();
for (Row l : list) {
if (l.hasValues()) {
Map<String, String> values = l.getResult(); // internal method of Row interface that returns a map
String key = values.get( "number");
map.put(key, values.get( "p_name" ));
}
}
The method works, but maybe it could be done better?
PS : There is an obvious error in my design. I wonder if you find it :)
Sine the key can have more then one values, what you are looking for is a MultiMap. Multimap
Or a simple map in the form
Map<Key,ArrayList<Values>>
There is no "fast" way here to me. You still need to iterate through all the elements and check all the values.
And actually hundreds to Java is not much at all
I have a Hashmap which may contain wildcards (*) in the String.
For instance,
HashMap<String, Student> students_;
can have John* as one key. I want to know if JohnSmith matches any elements in students_. There could be several matches for my string (John*, Jo*Smith, etc). Is there any way I can get a list of these matches from my HashMap?
Is there another object I could be using that does not require me to iterate through every element in my collection, or do I have to suck it up and use a List object?
FYI, my collection will have less than 200 elements in it, and ultimately I will want to find the pair that matches with the least amount of wildcards.
It's not possible to achieve with a hasmap, because of the hashing function. It would have to assign the hash of "John*" and the hash of "John Smith" et al. the same value.
You could make it with a TreeMap, if you write your own custom class WildcardString wrapping String, and implement compareTo in such a way that "John*".compareTo("John Smith") returns 0. You could do this with regular expressions like other answers have already pointed out.
Seeing that you want the list of widlcard matchings you could always remove entries as you find them, and iterate TreeMap.get()'s. Remember to put the keys back once finished with a name.
This is just a possible way to achieve it. With less than 200 elements you'll be fine iterating.
UPDATE: To impose order correctly on the TreeSet, you could differentiate the case of comparing two WildcardStrings (meaning it's a comparation between keys) and comparing a WildcardString to a String (comparing a key with a search value).
You can use regex to match, but you must first turn "John*" into the regex equivalent "John.*", although you can do that on-the-fly.
Here's some code that will work:
String name = "John Smith"; // For example
Map<String, Student> students_ = new HashMap<String, Sandbox.Student>();
for (Map.Entry<String, Student> entry : students_.entrySet()) {
// If the entry key is "John*", this code will match if name = "John Smith"
if (name.matches("^.*" + entry.getKey().replace("*", ".*") + ".*$")) {
// do something with the matching map entry
System.out.println("Student " + entry.getValue() + " matched " + entry.getKey());
}
}
You can just iterate your Map without converting it into a list, and use the String matches function, wih uses a regexp.
If you want to avoid the loop, you can use guava like this
#Test
public void hashsetContainsWithWildcards() throws Exception {
Set<String> students = new HashSet<String>();
students.add("John*");
students.add("Jo*Smith");
students.add("Bill");
Set<String> filteredStudents = Sets.filter(students, new Predicate<String>() {
public boolean apply(String string) {
return "JohnSmith".matches(string.replace("*", ".*"));
}
});
assertEquals(2, filteredStudents.size());
assertTrue(filteredStudents.contains("John*"));
assertTrue(filteredStudents.contains("Jo*Smith"));
}