Not able to generate a unique user-number - java

I have a problem when I'm trying to generate a unique customer-id in my application. I want the numbers to start from 1 and go up. I have a register-class using tree-map that generates the next customer-number using this code:
public String generateNumber()
{
int number = 1;
for(Map.Entry<String, Forsikringkunde> entry : this.entrySet())
{
if(entry.getValue().getNumber().equals(String.valueOf(number)))
{
number++;
}
}return String.valueOf(number);
}
When I generate customers in my application I get duplicates of the numbers even though I iterate through the map. When creating a customer I create the object, run this method, use a set-method for the ID and adds it to the register, but it doesn't work. Anyone have a solution?

If you're on Java 8, I suggest you try this:
int max = this.values()
.stream()
.map(Forsikringkunde::getNumber)
.mapToInt(Integer::parseInt)
.max()
.orElse(0);
return String.valueOf(max + 1);

Modify the code to instead find the maximum number in your map, and then use that+1:
public String generateNumber()
{
int max = -1;
for(Map.Entry<String, Forsikringkunde> entry : this.entrySet())
{
int entry = Integer.parseInt(entry.getValue().getNumber());
if(entry > max)
{
max = entry;
}
}
return String.valueOf(max + 1);
}
(This mimics your coding style. aioobe's answer shows how to do the same thing more elegantly.)
Your method doesn't work because the map is not iterated in order. For example, here's what happens if you iterate through two users with number 2 and 1 respectively:
Start with "number = 1"
Check if number == 2: it's not, so continue
Check if number == 1: it is, so set number = 2
Now the loop is done and number is 2, even though a user with id 2 already exists. If it had been iterated in order, it would have worked.

Related

Hackerrank: Frequency Queries Question Getting Timeout Error, How to optimize the code further?

I am getting timeout error for my code which I wrote using hashmap functions in java 8.When I submitted my answer 5 test cases failed due to timeout error out of 14 test cases on hackerrank platform.
Below is the question
You are given queries. Each query is of the form two integers described below:
x : Insert x in your data structure.
y : Delete one occurence of y from your data structure, if present.
z : Check if any integer is present whose frequency is exactly z. If yes, print 1 else 0.
The queries are given in the form of a 2-D array of where queries[i][0] contains the operation, and queries[i][1] contains the data element.
How should I optimize this code further ?
static HashMap<Integer,Integer> buffer = new HashMap<Integer,Integer>();
// Complete the freqQuery function below.
static List<Integer> freqQuery(List<List<Integer>> queries) {
List<Integer> output = new ArrayList<>();
output = queries.stream().map(query -> {return performQuery(query);}).filter(v -> v!=-1).collect(Collectors.toList());
//get the output array iterate over each query and perform operation
return output;
}
private static Integer performQuery(List<Integer> query) {
if(query.get(0) == 1){
buffer.put(query.get(1), buffer.getOrDefault(query.get(1), 0) + 1);
}
else if(query.get(0) == 2){
if(buffer.containsKey(query.get(1)) && buffer.get(query.get(1))>0 ){
buffer.put(query.get(1), buffer.get(query.get(1)) - 1);
}
}
else{
if(buffer.containsValue(query.get(1))){
return 1;
}
else{
return 0;
}
}
return -1;
}
public static void main(String[] args) {
List<List<Integer>> queries = Arrays.asList(
Arrays.asList(1,5),
Arrays.asList(1,6),
Arrays.asList(3,2),
Arrays.asList(1,10),
Arrays.asList(1,10),
Arrays.asList(1,6),
Arrays.asList(2,5),
Arrays.asList(3,2)
);
long start = System.currentTimeMillis();
System.out.println(freqQuery(queries));
long end = System.currentTimeMillis();
//finding the time difference and converting it into seconds
float sec = (end - start) / 1000F;
System.out.println("FreqQuery function Took "+sec + " s");
}
}
The problem with your code is the z operation. Sepecifically, the method containsValue has linear time complexty, making the whole complexity of the algorithm in the order of O(n*n). Here is a hint: add another hashmap on top of the one that you have which counts the occurences of occurences by value of the other map. In that way you can query directly this second one by the value (because it will be the key in this case).

ArrayList to Stream in Java by grouping

I would like to get the highest score group by Id .If two highest score's are same then i would like get the highest score based on lowest Optional ID.I would like to get it in Java Stream.So far this code works.Is there any efficient way to rewrite this code in java stream
Example :
records=record.Person(batchNumber);
List<Person> highestRecords = new ArrayList<>();for(
Person s:records)
{
if(!highestRecords.isEmpty()) {
boolean contains = false;
for(Person ns: new ArrayList<>(highestRecords)) {
if(s.Id().compareTo(ns.Id()) == 0) {
contains = true;
if(s.getScore.compareTo(ns.getScore()) > 0
&& s.optionalId().compareTo(ns.optionalId()) < 0) {
highestRecords.remove(ns);
highestRecords.add(s)
}
}
}
if(contains == false) {
highestRecords.add(s);
}
}else {
highestRecords.add(s);
}
}
}
Don't convert this to a stream.
There is no one pure operation happening here. There are several.
Of note is the initial operation:
if(getNewPendingMatches.size() > 0)
That's always going to be false on the first iteration and you're always going to add one element in.
On subsequent iterations, life gets weird because now you're trying to remove elements while iterating over them. A stream cannot delete values from itself while iterating over itself; it only ever processes in one direction.
As written this code should not be converted to a stream. You won't gain any benefits in doing so, and you're going to actively harm readability if you do.

How to generate 1000 unique email-ids using java

My requirement is to generate 1000 unique email-ids in Java. I have already generated random Text and using for loop I'm limiting the number of email-ids to be generated. Problem is when I execute 10 email-ids are generated but all are same.
Below is the code and output:
public static void main() {
first fr = new first();
String n = fr.genText()+"#mail.com";
for (int i = 0; i<=9; i++) {
System.out.println(n);
}
}
public String genText() {
String randomText = "abcdefghijklmnopqrstuvwxyz";
int length = 4;
String temp = RandomStringUtils.random(length, randomText);
return temp;
}
and output is:
myqo#mail.com
myqo#mail.com
...
myqo#mail.com
When I execute the same above program I get another set of mail-ids. Example: instead of 'myqo' it will be 'bfta'. But my requirement is to generate different unique ids.
For Example:
myqo#mail.com
bfta#mail.com
kjuy#mail.com
Put your String initialization in the for statement:
for (int i = 0; i<=9; i++) {
String n = fr.genText()+"#mail.com";
System.out.println(n);
}
I would like to rewrite your method a little bit:
public String generateEmail(String domain, int length) {
return RandomStringUtils.random(length, "abcdefghijklmnopqrstuvwxyz") + "#" + domain;
}
And it would be possible to call like:
generateEmail("gmail.com", 4);
As I understood, you want to generate unique 1000 emails, then you would be able to do this in a convenient way by Stream API:
Stream.generate(() -> generateEmail("gmail.com", 4))
.limit(1000)
.collect(Collectors.toSet())
But the problem still exists. I purposely collected a Stream<String> to a Set<String> (which removes duplicates) to find out its size(). As you may see, the size is not always equals 1000
999
1000
997
that means your algorithm returns duplicated values even for such small range.
Therefore, you'd better research already written email generators for Java or improve your own (for example, by adding numbers, some special characters that, in turn, will generate a plenty of exceptions).
If you are planning to use MockNeat, the feature for implementing email strings is already implemented.
Example 1:
String corpEmail = mock.emails().domain("startup.io").val();
// Possible Output: tiptoplunge#startup.io
Example 2:
String domsEmail = mock.emails().domains("abc.com", "corp.org").val();
// Possible Output: funjulius#corp.org
Note: mock is the default "mocking" object.
To guarantee uniqueness you could use a counter as part of the email address:
myqo0000#mail.com
bfta0001#mail.com
kjuy0002#mail.com
If you want to stick to letters only then convert the counter to base 26 representation using 'a' to 'z' as the digits.

program on arraylist java

System.out.println("Enter the appointment ID to see the full details :");
int y=in.nextInt();
int r;
for(r=0;r<count;r++)
{
if(all.get(r).getID()==y)
{
all.get(r).display();
}
}
I am using this code to retrieve the full details that have been entered using the get statement and display function. This is a small part of my program. I was wondering is there any other way to do it
A better way would be to use a HashMap<Integer,DetailsClass> instead of an ArrayList.
Then, instead of a loop, you'll just write :
HashMap<Integer,DetailsClass> map = new HashMap<>();
...
if (map.containsKey(y)) {
DetailsClass details = map.get(y);
details.display();
}
This makes the code simpler and more efficient, since searching for a key in a HashMap takes expected constant time, while searching the List takes linear time.
If you must use an ArrayList, at least leave the loop once you find the object you were looking for :
int y=in.nextInt();
for(int r=0;r<count;r++)
{
if(all.get(r).getID()==y)
{
all.get(r).display();
return; // or break; depending on where this for loop is located
}
}
Never loop over a List by index. You don't know what the internal implementation of the List is and looping might result on O(n^2) complexity.
I would suggest the following:
System.out.println("Enter the appointment ID to see the full details :");
final int y = in.nextInt();
for(final Thing thing : all) {
if(thing.getID() == y) {
thing.display();
}
}
Or, if you can use Java 8, then:
all.stream()
.filter(t -> t.getID() == y)
.findFirst()
.ifPresent(Thing::display);

Optimization of an Algo

I have code that reads a text file and creates an input array[] of boolean type. Its size is about 100,000-300,000 items. Now the problem I'm facing is to create all those subsets of size N, 3>=N>=9, that have contiguous true values.
E.g. for N=3, [true][true][true] is the required subset if all the 3 trues are in the continuous indexes.
Although I have an algorithm created, it's very slow. I need a better solution, which is fast and efficient.
Please suggest some ideas.
public static void createConsecutivePassingDays()
{
for (String siteName : sitesToBeTestedList.keySet())
{
System.out.println("\n*****************Processing for Site--->"+siteName+" ***********************");
LinkedHashMap<String,ArrayList<String>> cellsWithPassedTripletsDates=new LinkedHashMap<String, ArrayList<String>>();
for (String cellName : sitesToBeTestedList.get(siteName))
{
System.out.println("\n*****************Processing for Cell--->"+cellName+" ***********************");
boolean failed=false;
ArrayList<String> passedDatesTriplets=new ArrayList<String>();
int consecutiveDays=0;
String tripletDate="";
String prevDate_day="";
String today_Date="";
for (String date : cellDateKpiMetOrNotMap.get(cellName).keySet())
{
System.out.println("\nprocessing for Date-->"+date);
if(!(prevDate_day.trim().equals("")))
today_Date=getNextDay(prevDate_day.substring(0, prevDate_day.lastIndexOf('_')));
if(Connection.props.getProperty("INCLUDE_WEEKENDS").equalsIgnoreCase("FALSE"))
{
if(date.endsWith("SAT") || date.endsWith("SUN") || (!(date.substring(0, date.lastIndexOf('_')).equalsIgnoreCase(today_Date))))
{
if(consecutiveDays >= Reader.days)
{
passedDatesTriplets.add(tripletDate);
}
tripletDate="";
consecutiveDays=0;
prevDate_day=date;
continue;
}
}
if(cellDateKpiMetOrNotMap.get(cellName).get(date).equalsIgnoreCase("TRUE"))
{
if(tripletDate.equals(""))
tripletDate=date;
else
tripletDate+="#"+date;
consecutiveDays++;
}
else
{
failed=true;
if(consecutiveDays >= Reader.days)//kd
{
System.out.println("Triplet to be added-->"+tripletDate);
passedDatesTriplets.add(tripletDate);
}
tripletDate="";
consecutiveDays=0;
}
prevDate_day=date;
}
if(!failed)
passedDatesTriplets.add(tripletDate);
else
{
if(tripletDate.trim().split("#").length >= Reader.days)
{
passedDatesTriplets.add(tripletDate);
}
}
cellsWithPassedTripletsDates.put(cellName, passedDatesTriplets);
}
siteItsCellsWithPassedDates.put(siteName, cellsWithPassedTripletsDates);
}
System.out.println("\n************************************************SITES***************************************");
for (String site : siteItsCellsWithPassedDates.keySet())
{
System.out.println("\n********************Site="+site+" ***********************");
for (String cellName : siteItsCellsWithPassedDates.get(site).keySet())
{
System.out.println("\nCellName="+cellName);
System.out.println(siteItsCellsWithPassedDates.get(site).get(cellName));
}
System.out.println("***********************************************************");
}
System.out.println("********************************************************************************************");
}
First I would stay away from the array[boolean] a BitSet is more memory efficient in I'd expect it to be faster as well in your case. Since it will utilize the caches better. See boolean[] vs. BitSet: Which is more efficient?
For the algorithm:
Iterate through the datastructure.
When you come across the first true, remember its position (start) until you reach a false. This is the position end
At that point you have the start and end of a contiuous interval of true values, which is basically your result. You get your subsets as starting from start to end - n.
Repeat until the end of you datastructure
You can even parallize this by starting n-processes, each handling a different part of the array, starting with the first false value after the start of the segement and continuing over the end of the segement until the first false.
The simplest algo would be to check the N values starting at index x. if there is at least one false, then you can go directly to the index x+N. otherwise you can check index x+1;
if there is no valid sequence, then you will check size/N cells.
in pseudo-code :
int max = array.length - N;
int index = 0;
boolean valid = true;
while (index < max) {
valid = true;
for (check = index; check<index+N; check++){
valid = valid && array[check];
}
if (valid) {
// you got a continous sequence of true of size N
;
index++;
} else {
index = index + N;
}
}
also, with a BitSet instead of an array you could use the nextClearByte to get the index of the next false. the difference with the previous false minus N indicate the nomber of sequences of N true (with the previous false initially valued at -1).
I will sugggest you to create a stringbuilder and append 1 for every "true" value added to the boolean array and a 0 for every "false" added. Thus your stringbuilder will have a sequence of 1s and 0s. Then just use indexOf("111") to get the starting index of the three contiguous "true" values, it will be the starting index in the stringbuilder and in your boolean array as well.

Categories

Resources