I have a situation where I have set of Players in a Room and every Player will have set of cards in their hand.
HashMap<Integer,ArrayList<Integer>> useridToCardsinTheirHand = new HashMap<Integer, ArrayList<Integer>>();
Any Player can "Make a Call".
I need to check if the Player who has made a 'call' has the least value
(least value of the aggregate cards).
To Proceed with the above logic I use again an LinkedhashMap
private static LinkedhashMap<Integer,Integer> useridTotalRank = new LinkedhashMap<Integer,Integer>();
If there is a tie in the values then there will a priority algorithm carried on.
I use hashMap in all the logics.
I am facing problems since I am using HashMaps. The Logic flow is clumsy.
I am planning to make a redesign.I am going through MultiMap , But still anticipate the similar problem.
Can I have suggestions on the kind of Collections to be used.
The psuedo code I have tried is ::
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class NewCalling {
static HashMap<Integer,ArrayList<Integer>> useridToPointsmap = new HashMap<Integer, ArrayList<Integer>>();
lamposHAshMap hashmapsort = new lamposHAshMap();
private static HashMap<Integer,Integer> useridTotalRank = new HashMap<Integer,Integer>();
private static int jokercard = 0x27;
private static int closedjokercard =0x25 ;
private static List<Integer> faceCards = new ArrayList<Integer>();
#SuppressWarnings("unchecked")
public static void main(String args[]) {
/**
* Assuming the calling is made and the Player id is hard Coded
*/
boolean callingflag = true;
int callinguserid = 2;
/*************** Preparing the information which will be given by the ********/
ArrayList<Integer> cardsArray1 = new ArrayList<Integer>();
ArrayList<Integer> cardsArray2 = new ArrayList<Integer>();
ArrayList<Integer> cardsArray3 = new ArrayList<Integer>();
ArrayList<Integer> cardsArray4 = new ArrayList<Integer>();
cardsArray1.add(0x01);
cardsArray1.add(0x1A);
//cardsArray1.add(0x33);
cardsArray2.add(0x21);
cardsArray2.add(0x03);
cardsArray2.add(0x32);
cardsArray3.add(0x21);
cardsArray3.add(0x03);
cardsArray3.add(0x32);
cardsArray4.add(0x01);
cardsArray4.add(0x02);
cardsArray4.add(0x32);
cardsArray4.add(0x31);
useridToPointsmap.put(1,cardsArray1);
useridToPointsmap.put(2,cardsArray2);
useridToPointsmap.put(3,cardsArray3);
useridToPointsmap.put(4,cardsArray4);
faceCards.add(0,10);
faceCards.add(1,11);
faceCards.add(2,12);
faceCards.add(3,13);
/*************** Preparing the information which will be given by the ********/
if(callingflag)
{
int calledUserTp = totalPointsByUserid(callinguserid,jokercard);
System.out.println("Total Points of the User Who has made a Call is ::"+calledUserTp);
HashMap<Integer,Integer> useridTotalRankMap = totalPointsforEveryUser(jokercard);
LinkedHashMap<Integer,Integer> useridTotalRankMapSorted = new LinkedHashMap<Integer, Integer>();
useridTotalRankMapSorted = (LinkedHashMap<Integer, Integer>) sortByComparator(useridTotalRankMap);
for(Map.Entry<Integer, Integer> entry :useridTotalRankMapSorted.entrySet())
{
System.out.println( entry.getKey() +"----"+entry.getValue());
if(entry.getKey() == callinguserid )
{
System.out.println( "GOOD CALL");
break;
}
}
}
}
/** Gives the Cards Rank **/
static int getCardRank(int Cardhexvalue)
{
int rank = Cardhexvalue & 15;
return rank;
}
/** Gives the Cards Suit **/
static int getCardSuit(int Cardhexvalue)
{
int suit = (Cardhexvalue>>4);
return suit;
}
// METHODS REQUIRED
private static HashMap<Integer,Integer> totalPointsforEveryUser(int jokerCardVal)
{
for(Map.Entry<Integer, ArrayList<Integer>> entry :useridToPointsmap.entrySet())
{
int sum = 0;
int playerId = entry.getKey();
ArrayList<Integer> cardsList = entry.getValue();
for (Integer s : cardsList)
{
if (getCardRank(s) != getCardRank(jokerCardVal)) {
if (faceCards.contains(s))
{
sum += 10;
}
else
{
sum += getCardRank(s);
}
}
}
useridTotalRank.put(playerId, sum);
}
return useridTotalRank;
}
private static int totalPointsByUserid(int userId,int jokerCardVal)
{
ArrayList<Integer> cardsList = useridToPointsmap.get(userId);
int sum = 0;
for (Integer s : cardsList)
{
if (getCardRank(s) != getCardRank(jokerCardVal)) {
if (faceCards.contains(s))
{
sum += 10;
}
else
{
sum += getCardRank(s);
}
}
}
return sum;
}
#SuppressWarnings("unchecked")
private static Map sortByComparator(Map unsortMap) {
List list = new LinkedList(unsortMap.entrySet());
//sort list based on comparator
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getValue())
.compareTo(((Map.Entry) (o2)).getValue());
}
});
//put sorted list into map again
Map sortedMap = new LinkedHashMap();
for (Iterator it = list.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry)it.next();
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
private static boolean checkForNoDuplicates(HashMap<Integer, Integer > useridTotalRankMapSorted)
{
Collection<Integer> valuesList = useridTotalRankMapSorted.values();
Set<Integer> valuesSet = new HashSet<Integer>(useridTotalRankMapSorted.values());
System.out.println("-----"+ valuesList.size() +"----"+valuesSet.size());
if(valuesList.size() == valuesSet.size())
{
return true;
}
else
return false;
}
// Stack
public static HashMap getDuplicateValues(HashMap in)
{
// Clone input HashMap because we're removing stuff from it
in = (HashMap)in.clone();
HashMap rval = new HashMap();
Object[] keys = in.keySet().toArray();
// iterate through all keys
for(int x=0;x<keys.length;x++) {
Object value = in.get(keys[x]);
in.remove(keys[x]);
// if value is in input HashMap, store it in duplicate HashMap because it has another value
if(in.containsValue(value)) {
rval.put(keys[x],value);
}
// if value is in duplicate HashMap, store it also because it HAD another value earlier
if(rval.containsValue(value)) {
rval.put(keys[x],value);
}
}
return(rval);
}
public static HashMap<Object, ArrayList<Object>> gettingTheDuplicates(HashMap map) {
HashMap<Object, ArrayList<Object>> newMap = new HashMap<Object, ArrayList<Object>>();
Set<Entry> set = map.entrySet();
for(Entry entry : set) {
ArrayList list = new ArrayList();
if(newMap.containsKey(entry.getValue())) {
list=newMap.get(entry.getValue());
}
list.add(entry.getKey());
newMap.put(entry.getValue(), list);
}
return newMap;
}
private static void priorityCheck(int playerId1,int playerId2,int jokerCardVal)
{
int jokerCountPlayerOne = 0;
int jokerCountPlayerTwo = 0;
int openJokerCountPlayerOne = 0;
int openJokerCountPlayerTwo = 0;
List<Integer> playerOneCards = useridToPointsmap.get(playerId1);
List<Integer> playerTwoCards = useridToPointsmap.get(playerId2);
System.out.println("Current game player cards-----"+playerOneCards);
System.out.println("Tied game player cards--------"+playerTwoCards);
int playerOneCardCount = playerOneCards.size();
int playerTwoCardCount = playerTwoCards.size();
// Hard coded
// playerOneCardCount = 4;
//playerTwoCardCount = 4;
// jokerCountPlayerOne = 1;
// jokerCountPlayerTwo = 1;
//openJokerCountPlayerOne =1;
//openJokerCountPlayerTwo =2;
System.out.println("---jokerCardVal---"+jokerCardVal);
System.out.println("---playerOneCardCount---playerTwoCardCount"+playerOneCardCount+" "+playerTwoCardCount);
if (playerOneCards.contains(jokerCardVal))
{
openJokerCountPlayerOne++;
}
if (playerTwoCards.contains(jokerCardVal))
{
openJokerCountPlayerTwo++;
}
if (playerOneCards.contains(0))
{
jokerCountPlayerOne++;
}
if (playerTwoCards.contains(0))
{
jokerCountPlayerTwo++;
}
if (playerOneCardCount == playerTwoCardCount)
{
if (jokerCountPlayerOne == jokerCountPlayerTwo)
{
if (openJokerCountPlayerOne == openJokerCountPlayerTwo)
{
System.out.println("Still Tie Occurring---------------");
} else
{
if (openJokerCountPlayerOne > openJokerCountPlayerTwo)
{
System.out.println("First player has high rank based on open joker");
} else
{
System.out.println("Second player has high rank based on open joker");
}
}
} else
{
if (jokerCountPlayerOne > jokerCountPlayerTwo)
{
System.out.println("First player has high rank based on joker");
} else
{
System.out.println("Second player has high rank based on joker");
}
}
} else
{
if (playerOneCardCount < playerTwoCardCount)
{
System.out.println("First player has high rank based on Count");
} else
{
System.out.println("Second player has high rank based on count");
}
}
}
// New Priority Check
private static List<Integer> priorityNew(ArrayList<Integer> tocompare)
{
// ArrayList to array
Integer[] sortedArray = (Integer[]) tocompare.toArray();
bubble_srt(sortedArray,sortedArray.length);
List<Integer> mapValuesNew = Arrays.asList(sortedArray);
return mapValuesNew;
}
public static void bubble_srt( Integer a[], int n ){
int i, j,t=0;
for(i = 0; i < n; i++){
for(j = 1; j < (n-i); j++){
// System.out.print(" I am in first "+a[j-1]+" "+a[j] +"*********"+whichCardHigher(a[j-1],a[j]));
if(WhichuserHigher(a[j-1],a[j])){
t = a[j-1];
a[j-1]=a[j];
a[j]=t;
}
}
}
}
public static boolean WhichuserHigher(int user1,int user2)
{
if(getNumberofCards(user1) == getNumberofCards(user1) )
{
if(getNumberofJoker(user1) == getNumberofJoker(user2))
{
if(getNumberofClosedJoker(user1) == getNumberofClosedJoker(user2))
{
System.out.println("Its a Mega Tie");
}
else
{
if(getNumberofClosedJoker(user1) > getNumberofClosedJoker(user2))
{
return true;
}
else
{
return false;
}
}
}
else
{
if(getNumberofJoker(user1) > getNumberofJoker(user2))
{
return true;
}
else
{
return false;
}
}
}
else
{
if(getNumberofCards(user1) >getNumberofCards(user2))
{
return true;
}
else
{
return false;
}
}
return false;
}
public static int getNumberofCards(int user)
{
int noOfCards = 0;
for(Map.Entry<Integer, ArrayList<Integer>> entry :useridToPointsmap.entrySet())
{
if(entry.getKey() == user)
{
noOfCards = entry.getValue().size();
}
}
return noOfCards;
}
public static int getNumberofJoker(int user)
{
int noOfJokers = 0;
int count = 0;
for(Map.Entry<Integer, ArrayList<Integer>> entry :useridToPointsmap.entrySet())
{
if(entry.getKey() == user)
{
for(int i= 0 ;i< entry.getValue().size();i++)
{
if(Integer.parseInt(entry.getValue().toString()) == jokercard)
{
count ++;
}
}
}
}
noOfJokers = count;
return noOfJokers;
}
public static int getNumberofClosedJoker(int user)
{
int noOfClosedJokers = 0;
int count = 0;
for(Map.Entry<Integer, ArrayList<Integer>> entry :useridToPointsmap.entrySet())
{
if(entry.getKey() == user)
{
for(int i= 0 ;i< entry.getValue().size();i++)
{
if(Integer.parseInt(entry.getValue().toString()) == closedjokercard)
{
count ++;
}
}
}
}
noOfClosedJokers = count;
return noOfClosedJokers;
}
}
Please have simple Java beans for Room, Player and Card (probably for Card may not be necessary) etc. This way you can change the properties of the classes when new requirement comes in the future. Ultimately you need to manage only List Room, so that if you get an Room object you can easily retrieve the Players from it and so on.
Class Room{
String roomName;
String location;
String List<Player>;
// have getters setters for each of them
}
This way it is more manageable as well, so that processing code if any present you can put them in the related classes only. for e.g. In the room class you can have a method called getLeastValueCard which returns for that Room which user and you can have loop for entire Rooms.
Hope this make sense.
Related
I have a text file containing the following strings (which are versions of a software):
1_10_2_0_154
3_10_5_2_10
2_10_4_1
3_10_5_1_37
I'm trying to find the most recent version, in this case 3_10_5_2_10 is the version that I'm trying to display using java.
For the moment, here is my code:
BufferedReader br;
String version;
ArrayList<List<Integer>> array = new ArrayList<List<Integer>>();
List<Integer> liste = new ArrayList<Integer>();
try{
br = new BufferedReader(new FileReader(new File(FILEPATH)));
while((version= br.readLine()) != null)
{
liste = Arrays.asList(version.split("_")).stream().
map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
array.add(liste);
}
for(int i = 0; i < array.size(); i++)
{
for (List l: array)
{
Object z = l.get(i);
List<Object> listes = new ArrayList<Object>();
listes.add(z);
System.out.println(listes);
}
}
br.close();
System.out.println(array);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
I made a loop to save strings to ArrayList> like:
[[1,10,2,0,154] , [3,10,5,2,10], [2,10,4,1], [3,10,5,1,37]]
I want to get the elements of each list and compare them to find the most biggest one (most recent one) but I don't know to do that..
I sugguest you a object approach, define a class named Version with compareTo method, then using method sort on Collections class you can simply sort your versions.
Advantages
Clean and Clear code
Data validation
Main:
public class Main {
public static void main(String[] args){
List<Version> versions = Arrays.asList(
Version.create("1_10_2_0_154"),
Version.create("3_10_5_2_10"),
Version.create("2_10_4_1_49"),
Version.create("3_10_5_1_37"));
versions.sort(Version::compareTo);
System.out.println(versions.get(0).toString());
}
}
Version:
public class Version implements Comparable<Version> {
private final int major;
private final int minor;
private final int bug;
private final int release;
private final int build;
public Version(int major, int minor, int bug, int release, int build) {
this.major = major;
this.minor = minor;
this.bug = bug;
this.release = release;
this.build = build;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getBug() {
return bug;
}
public int getRelease() {
return release;
}
public int getBuild() {
return build;
}
#Override
public String toString() {
return "Version{" +
"major=" + major +
", minor=" + minor +
", bug=" + bug +
", release=" + release +
", build=" + build +
'}';
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return create(intValues);
}
public static Version create(List<Integer> values){
if(Objects.requireNonNull(values).size() < 5)
throw new IllegalArgumentException();
return new Version(
values.get(0),
values.get(1),
values.get(2),
values.get(3),
values.get(4)
);
}
#Override
public int compareTo(Version that) {
if (this.major > that.major) {
return -1;
} else if (this.major < that.major) {
return 1;
}
if (this.minor > that.minor) {
return -1;
} else if (this.minor < that.minor) {
return 1;
}
if (this.bug > that.bug) {
return -1;
} else if (this.bug < that.bug) {
return 1;
}
if (this.release > that.release) {
return -1;
} else if (this.release < that.release) {
return 1;
}
if (this.build > that.build) {
return -1;
} else if (this.build < that.build) {
return 1;
}
return 0;
}
}
UPDATE 1
As suggested by #Henrik i updated the list sorting with a Java 8 approach.
UPDATE 2
I reversed the compareTo method so now you can simply do plain sort calling sort method on list and passing method reference Version::compareTo
UPDATE 3
A more dynamic solution for Version class:
public class Version implements Comparable<Version> {
private final List<Integer> values;
public Version(List<Integer> values) {
this.values = values;
}
public List<Integer> getValues() {
return values;
}
#Override
public String toString() {
return String.join("_", values
.stream()
.map(Object::toString)
.collect(Collectors.toList()));
}
#Override
public int compareTo(Version that) {
List<Integer> thatValues = that.getValues();
for(int index = 0; index < values.size(); index++){
Integer value = values.get(index);
Integer thatValue = thatValues.get(index);
if (value > thatValue) {
return -1;
} else if (value < thatValue) {
return 1;
}
}
return 0;
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return new Version(intValues);
}
}
You can write a Comparator to compare two Lists
Comparator<List<Integer>> comparator = (list1, list2) -> {
Iterator<Integer> iteratorA = list1.iterator();
Iterator<Integer> iteratorB = list2.iterator();
//It iterates through each list looking for an int that is not equal to determine which one precedes the other
while (iteratorA.hasNext() && iteratorB.hasNext()) {
int elementA = iteratorA.next();
int elementB = iteratorB.next();
if (elementA > elementB) {
return 1;
} else if (elementA < elementB) {
return -1;
}
}
//All elements seen so far are equal. Use the list size to decide
return iteratorA.hasNext() ? 1 : iteratorB.hasNext() ? -1 : 0;
};
You can sort it as
Collections.sort(list, comparator);
EDIT: You can refer to David Geirola's answer to convert the version string as a POJO and move the comparator logic inside that. But that is highly tied/coupled to the input string format. My solution works for any List<List<Integer>>.
A simple object oriented approach would be to create object, representing version number, let's call it VersionNumber, which would have a constructor of a factory method that does the parsing of the string. This VersionNumber class should implement interface Comparable and implement method compareTo.
Here is a hint for using Comparable Why should a Java class implement comparable?
Then you can easily write an algorithm to find the max version or google some library that would do it for you.
It is not optimized but should work. You can use both of comparators.
static List<String> versions = Arrays.asList(
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37");
static Comparator<List<Integer>> c = (o1,o2) -> {
int length = o1.size()>o2.size()?o2.size():o1.size();
for (int i = 0; i < length; i++) {
int i1 = o1.get(i);
int i2 = o2.get(i);
if (i1 != i2)
return i1 - i2;
}
return 0;
};
static Comparator<List<Integer>> c2 = (o1,o2) -> {
Iterator<Integer> i1=o1.iterator();
Iterator<Integer> i2=o2.iterator();
while (i1.hasNext() && i2.hasNext()){
int i = i1.next()-i2.next();
if (i!=0) return i;
}
return 0;
};
static Optional<List<Integer>> getTheMostRecentVersion(List<String> versions) {
return versions.stream().
map(s -> Arrays.stream(s.split("_")).
map(Integer::parseInt).
collect(Collectors.toList())).max(c2);
}
I think that this text file could be very big and it is better to compare each line on the fly (instead of store all line into collection to sort it after):
public static String getMostRecentVersion(BufferedReader in) throws IOException {
final Comparator<String[]> version = (s1, s2) -> {
int res = 0;
for (int i = 0; i < 5 && res == 0; i++)
res = Integer.compare(Integer.parseInt(s1[i]), Integer.parseInt(s2[i]));
return res;
};
String str;
String resStr = null;
String[] resPparts = null;
while ((str = in.readLine()) != null) {
String[] parts = str.split("_");
if (resStr == null || version.compare(parts, resPparts) > 0) {
resStr = str;
resPparts = parts;
}
}
return resStr;
}
A general ListComparator should help.
static class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {
#Override
public int compare(List<T> o1, List<T> o2) {
for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
int diff =
// Off the end of both - same.
i >= o1.size() && i >= o2.size() ? 0
// Off the end of 1 - the other is greater.
: i >= o1.size() ? -1
: i >= o2.size() ? 1
// Normal diff.
: o1.get(i).compareTo(o2.get(i));
if (diff != 0) {
return diff;
}
}
return 0;
}
}
private static final Comparator<List<Integer>> BY_VERSION = new ListComparator<Integer>().reversed();
public void test(String[] args) {
String[] tests = {
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37",
"3_10_5_1_37_0"
};
System.out.println("Before: " + Arrays.toString(tests));
System.out.println("After: " + Arrays.stream(tests)
// Split into parts.
.map(s -> s.split("_"))
// Map String[] to List<Integer>
.map(a -> Arrays.stream(a).map(s -> Integer.valueOf(s)).collect(Collectors.toList()))
// Sort it.
.sorted(BY_VERSION)
// Back to a new list.
.collect(Collectors.toList()));
}
slap your arrays together into a number then just do number comparison.
class Scratch
{
public static void main(String[] args)
{
List<List<Integer>> arr = new ArrayList<>();
arr.add(fromArray(new Integer[]{1,10,2,0,154}));
arr.add(fromArray(new Integer[]{3,10,5,2,10}));
arr.add(fromArray(new Integer[]{2,10,4,1,49}));
arr.add(fromArray(new Integer[]{3,10,5,1,37}));
Integer[] maxLengths = {0,0,0,0,0};
for (List<Integer> v : arr)
{
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int curMaxLen = maxLengths[idx];
maxLengths[idx] = Math.max(n.toString().length(), curMaxLen);
}
}
Long largest = arr.stream().map(v -> {
StringBuilder result = new StringBuilder();
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int maxLen = maxLengths[idx];
result.append(String.format("%-" + maxLen + 's', n).replace(' ', '0'));
}
return result.toString();
}).map(Long::valueOf).max(Comparator.naturalOrder()).get();
System.out.println(largest);
}
public static List<Integer> fromArray(Integer[] array)
{
List<Integer> list = new ArrayList<>();
Collections.addAll(list, array);
return list;
}
}
I got this problem I need to return the key in a hashmap with the largest value, the trick here is that the method must account for edge case scenarios. I can also only use the above imports, so Map.Entry is not allowed. Collections.sort isn't etc. Thanks.
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class Exercise {
public static String findLargest(HashMap<String, Integer> map) {
// Enter code here
if(that.isEmpty()) return "";
Integer maxInt = Integer.MIN_VALUE;
String maxCity = "";
for(String entry : that.keySet()) {
if (that.get(entry) != null && that.get(entry) < Integer.MAX_VALUE && that.get(entry) > Integer.MIN_VALUE && that.get(entry) > maxInt) {
maxInt = that.get(entry);
maxCity = entry;
}
}
return maxCity;
}
public static void check(String largest, List<String> apples, List<Integer> size) {
HashMap<String, Integer> map = new HashMap<>();
for (int i = 0; i < apples.size(); i++) {
map.put(apples.get(i), size.get(i));
}
assert largest.equals(findLargest(map)) : "expected " + largest + " but was " + findLargest(map);
}
public static void main(String[] arg) {
check("Granny", Arrays.asList("Granny", "Eve", "Rose"), Arrays.asList(5, 1, 2));
}
}
The solution is really inefficient, but if you cannot add any other imports... it works. The first step is to find the maximum value among the integers and then for each of the keys, check if the map.get(key).equals(max):
public static String findLargest(HashMap<String, Integer> map) {
//step 1
int max = Integer.MIN_VALUE;
for (int i : map.values()) {
max = Math.max(max, i);
}
//step 2
for (String str : map.keySet()) {
if (map.get(str).equals(max)) {
return str;
}
}
return null;
}
I have a continuous running thread in my application, which consists of a HashSet to store all the symbols inside the application. As per the design at the time it was written, inside the thread's while true condition it will iterate the HashSet continuously, and update the database for all the symbols contained inside HashSet.
The maximum number of symbols that might be present inside the HashSet will be around 6000. I don't want to update the DB with all the 6000 symbols at once, but divide this HashSet into different subsets of 500 each (12 sets) and execute each subset individually and have a thread sleep after each subset for 15 minutes, so that I can reduce the pressure on the database.
This is my code (sample code snippet)
How can I partition a set into smaller subsets and process (I have seen the examples for partitioning ArrayList, TreeSet, but didn't find any example related to HashSet)
package com.ubsc.rewji.threads;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskerThread extends Thread {
private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
String symbols[] = new String[] { "One", "Two", "Three", "Four" };
Set<String> allSymbolsSet = Collections
.synchronizedSet(new HashSet<String>(Arrays.asList(symbols)));
public void addsymbols(String commaDelimSymbolsList) {
if (commaDelimSymbolsList != null) {
String[] symAr = commaDelimSymbolsList.split(",");
for (int i = 0; i < symAr.length; i++) {
priorityBlocking.add(symAr[i]);
}
}
}
public void run() {
while (true) {
try {
while (priorityBlocking.peek() != null) {
String symbol = priorityBlocking.poll();
allSymbolsSet.add(symbol);
}
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
while (ite.hasNext()) {
String symbol = ite.next();
if (symbol != null && symbol.trim().length() > 0) {
try {
updateDB(symbol);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateDB(String symbol) {
System.out.println("THE SYMBOL BEING UPDATED IS" + " " + symbol);
}
public static void main(String args[]) {
TaskerThread taskThread = new TaskerThread();
taskThread.start();
String commaDelimSymbolsList = "ONVO,HJI,HYU,SD,F,SDF,ASA,TRET,TRE,JHG,RWE,XCX,WQE,KLJK,XCZ";
taskThread.addsymbols(commaDelimSymbolsList);
}
}
With Guava:
for (List<String> partition : Iterables.partition(yourSet, 500)) {
// ... handle partition ...
}
Or Apache Commons:
for (List<String> partition : ListUtils.partition(yourList, 500)) {
// ... handle partition ...
}
Do something like
private static final int PARTITIONS_COUNT = 12;
List<Set<Type>> theSets = new ArrayList<Set<Type>>(PARTITIONS_COUNT);
for (int i = 0; i < PARTITIONS_COUNT; i++) {
theSets.add(new HashSet<Type>());
}
int index = 0;
for (Type object : originalSet) {
theSets.get(index++ % PARTITIONS_COUNT).add(object);
}
Now you have partitioned the originalSet into 12 other HashSets.
We can use the following approach to divide a Set.
We will get the output as
[a, b]
[c, d]
[e]`
private static List<Set<String>> partitionSet(Set<String> set, int partitionSize)
{
List<Set<String>> list = new ArrayList<>();
int setSize = set.size();
Iterator iterator = set.iterator();
while(iterator.hasNext())
{
Set newSet = new HashSet();
for(int j = 0; j < partitionSize && iterator.hasNext(); j++)
{
String s = (String)iterator.next();
newSet.add(s);
}
list.add(newSet);
}
return list;
}
public static void main(String[] args)
{
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
int size = 2;
List<Set<String>> list = partitionSet(set, 2);
for(int i = 0; i < list.size(); i++)
{
Set<String> s = list.get(i);
System.out.println(s);
}
}
If you are not worried much about space complexity, you can do like this in a clean way :
List<List<T>> partitionList = Lists.partition(new ArrayList<>(inputSet), PARTITION_SIZE);
List<Set<T>> partitionSet = partitionList.stream().map((Function<List<T>, HashSet>) HashSet::new).collect(Collectors.toList());
The Guava solution from #Andrey_chaschev seems the best, but in case it is not possible to use it, I believe the following would help
public static List<Set<String>> partition(Set<String> set, int chunk) {
if(set == null || set.isEmpty() || chunk < 1)
return new ArrayList<>();
List<Set<String>> partitionedList = new ArrayList<>();
double loopsize = Math.ceil((double) set.size() / (double) chunk);
for(int i =0; i < loopsize; i++) {
partitionedList.add(set.stream().skip((long)i * chunk).limit(chunk).collect(Collectors.toSet()));
}
return partitionedList;
}
A very simple way for your actual problem would be to change your code as follows:
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
int i = 500;
while ((--i > 0) && ite.hasNext()) {
A general method would be to use the iterator to take the elements out one by one in a simple loop:
int i = 500;
while ((--i > 0) && ite.hasNext()) {
sublist.add(ite.next());
ite.remove();
}
This short program makes a binary file called data.bin with a bunch of randomly generated items that are 1024 bytes each. where the first 24 bytes of each item is the key. so how do i read each item from the data.bin file and do an external merge sort on it all?
import java.math.*;
import java.io.*;
import java.util.*;
public class CreateRandomDataFile {
public static void main(String[] args) throws Exception {
RandomAccessFile data = new RandomAccessFile("data.bin","rws");
Random r = new Random(482010);
Scanner input = new Scanner(System.in);
int number = 100000;
byte[] item = new byte[1024];
System.out.print("How many items (perhaps 800000)\n> ");
number = input.nextInt();
for (int i=0; i<number; i++) {
r.nextBytes(item);
data.write(item);
}
data.close();
System.out.println("Done");
}
}
look at http://www.vogella.com/articles/JavaAlgorithmsMergesort/article.html
Making this work on any object with a comparator:
package com.sel2in.sort;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/** based on http://www.vogella.com/articles/JavaAlgorithmsMergesort/article.html */
public class MergeSort<T> {
private List<T> items;
private List<T> helper;
private Comparator<T> comprtr;
private int cnt;
public void sort(T[] values, Comparator<T> comprtr) {
items = new ArrayList<T>();
items.addAll(Arrays.asList(values));
cnt = values.length;
this.helper = new ArrayList<T>(cnt);
this.comprtr = comprtr;
mergesort(0, cnt - 1);
}
public void sort(List<T> values, Comparator<T> comprtr) {
items = values;
//items.addAll(Arrays.asList(values));
cnt = values.size();
this.helper = new ArrayList<T>(cnt);
helper.addAll(items);
this.comprtr = comprtr;
mergesort(0, cnt - 1);
}
private void mergesort(int low, int high) {
// Check if low is smaller then high, if not then the array is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
mergesort(low, middle);
// Sort the right side of the array
mergesort(middle + 1, high);
// Combine them both
merge(low, middle, high);
}
}
private void merge(int low, int middle, int high) {
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
// helper[i] = items[i];
helper.set(i, items.get(i));
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest values from either the left or the right side back
// to the original array
while (i <= middle && j <= high) {
int cm = comprtr.compare(helper.get(i), helper.get(j));
//(helper[i] <= helper[j])
if (cm <= 0) {
//items[k] = helper[i];
items.set(k, helper.get(i));
i++;
} else {
//items[k] = helper[j];
items.set(k, helper.get(j));
j++;
}
k++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
//items[k] = helper[i];
items.set(k, helper.get(i));
k++;
i++;
}
}
}
String Comparator that works on entry type - useful for you as you have key and rest of line, we could have made our own object did not have to use Entry but its already there
package com.sel2in.sort;
import java.util.Comparator;
import java.util.Map.Entry;
/** compare 2 strings, taken from the key of a Map entry - Tushar Kapila */
public class MapStrKeyComparator implements Comparator<java.util.Map.Entry<String,Object>> {
#Override
public int compare(Entry<String,Object> o1, Entry<String,Object> o2) {
String s = o1.getKey().toString();
String n = o2.getKey().toString();
return s.compareTo(n);
}
}
Test
package com.sel2in.sort;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class TstMege {
/**
* #param args
*/
public static void main(String[] args) {
Map<String, String>mp = new HashMap<String, String>();
//here instead of the test values load from your file and seperate key and value
mp.put("tt", "nxcn3er3e33");
mp.put("aa", "gjkrmt454");
mp.put("zz", "rft56GDD");
mp.put("zz", "rft56GDD");
//sort
Set<Entry<String, String>> entries = mp.entrySet();
MapStrKeyComparator cpmr = new MapStrKeyComparator();
MergeSort sorter = new MergeSort();
//sort. sort(List<T> values, Comparator<T> comprtr)
ArrayList<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(entries.size());
lst.addAll(entries);
System.out.println("before " + lst);
sorter.sort(lst, cpmr);
System.out.println("sorted " + lst);
}
}
Output
before [tt=nxcn3er3e33, zz=rft56GDD, aa=gjkrmt454]
sorted [aa=gjkrmt454, tt=nxcn3er3e33, zz=rft56GDD]
Our own entry class
package com.sel2in.sort;
import java.util.Map.Entry;
public class TEntry<K,V> implements Entry<K, V> {
final K key;
V value;
TEntry(){
key = null;
}
TEntry(K k){
key = k;
}
TEntry(K k, V v) {
value = v;
key = k;
}
#Override
public K getKey() {
return key;
}
#Override
public V getValue() {
return value;
}
#Override
public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public String toString(){
return key + ":" + value;
}
//can copy hashcode , equals but not important now
}
File read binary and sort
package com.sel2in.sort;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map.Entry;
public class TstFileMegeSort {
/**
* #param args
*/
public static void main(String[] args) {
//Map<String, String>mp = new HashMap<String, String>();
ArrayList<Entry<String, String>> lst = new ArrayList<Entry<String, String>> ();
TEntry<String, String> en = null;
//here instead of the test values load from your file and seperate key and value
try {
RandomAccessFile data = new RandomAccessFile("data.bin","rws");
long l = data.length();
long recs = l / 1024;
long cnt = 0;
byte []b = new byte[1024];
while(cnt < recs){
cnt++;
data.readFully(b);
byte []key = Arrays.copyOfRange(b, 0, 24);
byte []value = Arrays.copyOfRange(b, 24, 1024);
en = new TEntry<String, String>(new String(key), new String(value));
lst.add(en);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//sort
//Set<Entry<String, String>> entries = mp.entrySet();
MapStrKeyComparator cpmr = new MapStrKeyComparator();
MergeSort sorter = new MergeSort();
//sort. sort(List<T> values, Comparator<T> comprtr)
//ArrayList<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(entries.size());
//lst.addAll(entries);
System.out.println("before " + lst);
sorter.sort(lst, cpmr);
System.out.println("sorted " + lst);
}
}
The problem is the following. There are multiple rows that have non-unique identifiers:
id value
0: {1,2,3}
0: {1,2,2}
1: {1,2,3}
2: {1,2,3}
2: {1,1,3}
I have the function equals that can compare multiple rows between each other. I need to write a code that selects the rows as an input of the function equals. The rows selected must have unique ids, BUT I should check all possible combinations of unique ids. For instance, if there are 5 rows with ids: 0,0,1,2,3, then I should check the following two combinations of ids: 0,1,2,3 and 0,1,2,3, because 0 apears twice. Of course, each of these two combinations will consist of unique rows that have id=0.
My code snippet is the following:
public class Test {
public static void main(String[] args) {
ArrayList<Row> allRows = new ArrayList<Row>();
allRows.add(new Row(0,new int[]{1,2,3}));
allRows.add(new Row(0,new int[]{1,2,2}));
allRows.add(new Row(1,new int[]{1,2,3}));
allRows.add(new Row(2,new int[]{1,2,3}));
allRows.add(new Row(2,new int[]{1,1,3}));
boolean answer = hasEqualUniqueRows(allRows);
}
private boolean hasEqualUniqueRows(ArrayList<Row> allTokens) {
for (int i=0; i<allTokens.size(); i++) {
ArrayList<Integer[]> rows = new ArrayList<Integer[]>();
rows = findUniqueRows(i,allTokens);
boolean answer = equalsExceptForNulls(rows);
if (answer) return true;
}
return false;
}
// Compare rows for similarities
public static <T> boolean equalsExceptForNulls(ArrayList<T[]> ts) {
for (int i=0; i<ts.size(); i++) {
for (int j=0; j<ts.size(); j++) {
if (i != j) {
boolean answer = equals(ts.get(i),ts.get(j));
if (!answer) return false;
}
}
}
return true;
}
public static <T> boolean equals(T[] ts1, T[] ts2) {
if (ts1.length != ts2.length) return false;
for(int i = 0; i < ts1.length; i++) {
T t1 = ts1[i], t2 = ts2[i];
if (t1 != null && t2 != null && !t1.equals(t2))
return false;
}
return true;
}
class Row {
private String key;
private Integer[] values;
public Row(String k,Integer[] v) {
this.key = k;
this.values = v;
}
public String getKey() {
return this.key;
}
public Integer[] getValues() {
return this.values;
}
}
}
Since the number of rows with unique ids is apriori unknown, I don´t know how to solve this problem. Any suggestions? Thanks.
Edit#1
I updated the code. Now it´s more complete. But it lacks the implementation of the function findUniqueRows. This function should select rows from the ArrayList that have unique keys (ids). Could someone help me to develop this function? Thanks.
Assuming the objective is to find every combination without duplicates you can do this with the following. The test to find duplicates is just to confirm it doesn't generate any duplicates in the first place.
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String... args) {
Bag<Integer> b = new Bag<>();
b.countFor(1, 2);
b.countFor(2, 1);
b.countFor(3, 3);
Set<String> set = new LinkedHashSet<>();
for (List<Integer> list : b.combinations()) {
System.out.println(list);
String s = list.toString();
if (!set.add(s))
System.err.println("Duplicate entry " + s);
}
}
}
class Bag<E> {
final Map<E, AtomicInteger> countMap = new LinkedHashMap<>();
void countFor(E e, int n) {
countMap.put(e, new AtomicInteger(n));
}
void decrement(E e) {
AtomicInteger ai = countMap.get(e);
if (ai.decrementAndGet() < 1)
countMap.remove(e);
}
void increment(E e) {
AtomicInteger ai = countMap.get(e);
if (ai == null)
countMap.put(e, new AtomicInteger(1));
else
ai.incrementAndGet();
}
List<List<E>> combinations() {
List<List<E>> ret = new ArrayList<>();
List<E> current = new ArrayList<>();
combinations0(ret, current);
return ret;
}
private void combinations0(List<List<E>> ret, List<E> current) {
if (countMap.isEmpty()) {
ret.add(new ArrayList<E>(current));
return;
}
int position = current.size();
current.add(null);
List<E> es = new ArrayList<>(countMap.keySet());
if (es.get(0) instanceof Comparable)
Collections.sort((List) es);
for (E e : es) {
current.set(position, e);
decrement(e);
combinations0(ret, current);
increment(e);
}
current.remove(position);
}
}