I'm working on a Java class that gets parameters from an "Account Request" form (like 'First Name', 'Last Name', 'email', etc.).
The Java class first gets the parameters from the form. It then initializes a user name with the first and last name strings like so:
String userName = firstName.substring(0,1).toLowerCase() + lastName.toLowerCase();
For example, the username for "Jake Smith" would be jsmith.
Afterwards, it checks to see if this 'userName' exists in the database. Obviously, "Jake Smith" and "John Smith" would create identical user names, "jsmith". To account for this, I'd just like to append numbers, starting with 1, to any matching user names.
How can I append a unique number at the end of each and every conflicting username (starting with 1 and incremented by 1 for each additional conflict)?
Obviously, a more elegant solution would be to allow the user to specify their user name, but this is how the mock client wants the project to be completed.
Thank you!
You could use String.format, something like:
String.format("%s%d", username, i++);
A "dumb" solution, but if it's just for tests...
private String getUsername(){
String userName = firstName.substring(0,1).toLowerCase() + lastName.toLowerCase();
int i=1;
while(usernameExists(userName)){
userName = userName.replaceAll("\\d+$","") + i++;
}
return userName;
}
Considering that userName don't have digits in the end.
Use a StringBuilder to construct the new string and StringBuilder#toString to obtain it.
Here's a simple method that uses a Map to keep track of ids.
class UniqueUsername {
private static Map<String, Integer> ids = new HashMap<String, Integer>();
public static String getUniqueUsername(String username) {
if (!ids.containsKey(username)) {
ids.put(username, new Integer(0));
return username;
}
ids.put(username, ids.get(username)+1);
return username + ids.get(username);
}
}
If conflicts are unlikely then you could just loop until unique, staring at 1 and adding 1 each time
For example:
i=0;
String usernameToTry=username;
while (notUnique(usernameToTry)) {
i++;
usernameToTry=username+i;
}
If conflicts are likely then you may find this approach unsatisfactory because of the performance penalty of hitting the database (to check if unique) for every iteration of the loop. For example, if you have jsmith100 already then you don't want to check 100 times before coming up with jsmith101.
Related
public String searchNumber(String name){
String result = "";
for(Person search: person){
if(search.getName().contains(name)){
result += search.getNumber();
}
else{
result = " number not known ";
}
}
return result;
}
Looking for some advice here on how to fix this problem I am having. This is a method which I expect to use my getName method to see if the local instance (name) is within the ArrayList. However, I am only getting the latter result to display only, saying "number not known." My step-by-step process goes like this: I create an instance of Person (search), access the getName method, access the contains method since it is originally a String method, and then check to see if the local instance is within the arrayList. If my logic is incorrect, please correct me. Also, does accessing the person array prevent me from using a String type in my for-each loop, since it is a Person object? I tried do this with a String type, but could not continue further since I could not convert to a String within the for-each loop.
Here's a breakdown of your current code:
You consider every object in the person list. If that person's name matches the parameter, you get the number from it. Otherwise, you set result to the error message. Note that the otherwise clause is applied for EACH person, instead of at the end if NOBODY was found to have the same name. That is, even if you find the right person and assign result to their number, if the next person isn't correct then you overwrite result to the error message again.
To make sure the error message is only assigned once and only if NOBODY is found, you need to check whether that is true after going through everyone (since you can't know if nobody is found before checking everyone!). The trick now is to find some clause which is always true when nobody was found. But that can just be if result was never modified. That is, you can set result to the default value at declaration, then only modify it to a number if the right person was found. Also, I am assuming that only one person should be found and you don't want to actually concatenate the numbers together (which is what you are doing by using +=). That said, try this:
public String searchNumber(String name){
for (Person search: person){
if (search.getName().contains(name)){
return search.getNumber();
}
}
return " number not known ";
}
Basically you can just return after finding your record
String notFound = " number not known ";
for(Person search: person){
if(search.getName().contains(name)){
return search.getNumber();
}
}
return notFound;
String result = null;
for(Person search: person){
if(search.getName().contains(name)){
result += search.getNumber();
}
}
if(result == null){
result = "number not known ";
}
return result;
Since there is no way to tell the last element in for-in loop, so the alternative is basing on result == null
I am creating a mock Twitter project which loads user data from a somewhat large text file containing ~3.6 million lines formatted like this:
0 12
0 32
1 9
1 54
2 33
etc...
The first string token is the userId and the second is the followId.
The first half of this helper method takes in the current user's ID, checks to see if it exists and creates a new user if necessary. After that, the followId is added to this new or existing user's following list of type ArrayList<Integer>.
With ~3.6 million lines to read, this doesn't take long (9868 ms).
Now the second half creates or finds the followed user (followId) and adds the userId to their followers list, but this additional code extends the amount of time to read the file exponentially (172744 ms).
I tried using the same TwitterUser object throughout the method. All of the adding methods (follow, addFollower) are simple ArrayList.add() methods. Is there anything I can do to make this method more efficient?
Please note: While this is school-related, I'm not asking for an answer to my solution. My professor permitted this slow object initialization, but I'd like to understand how I can make it faster.
private Map<Integer, TwitterUser> twitterUsers = new HashMap<Integer, TwitterUser>();
private void AddUser(int userId, int followId){
TwitterUser user = getUser(userId);
if (user == null){
user = new TwitterUser(userId);
user.follow(followId);
twitterUsers.putIfAbsent(userId, user);
} else{
user.follow(followId);
}
//adding the code below, slows the whole process enormously
user = getUser(followId);
if (user == null){
user = new TwitterUser(followId);
user.addFollower(userId);
twitterUsers.putIfAbsent(followId, user);
} else{
user.addFollower(userId);
}
}
private TwitterUser getUser(int id){
if (twitterUsers.isEmpty()) return null;
return twitterUsers.get(id);
}
If putIfAbsent(int, User) does what you would expect it to do, that is: checking if it's there before inserting, why do you use it within an if block whose condition already checks if the user is there?
In other words, if fetching a user returned a null value you can safely assume that the user was not there.
Now I'm not too sure about the internal workings of the *putIfAbsent* method (probably it would loop through the set of the keys in the map), but intuitively I would expect a normal put(int, User) to perform better, even more with a map that gets as large as yours as the input file gets scanned through.
Therefore I would suggest to try something like:
user = getUser(followId);
if (user == null){
user = new TwitterUser(followId);
user.addFollower(userId);
twitterUsers.put(followId, user);
} else{
user.addFollower(userId);
}
which would apply to the first half as well.
Actually i want to check if there is any user object with given username and password and return the user from the list of users. can you guys tell me the easiest way to implement that. thanks in advance.
You can do a Map of maps. The outer map being usernames, and the inner passwords. That is Map< String, Map< String, User >>
More appropriate might be to create an object User with {username, password} fields and do a Set which overrides equals and hash to something like this:
class User {
String username;
String password;
equals(Object other){
return other.username.equals(this.username) && other.password.equals(this.password);
}
hashCode() { //hash the two values together
return (username+password).hashCode();
}
}
And then have a Set of users Set< User >, called set.
checkIfUserValid(String user, String password){
u = new User(user, password);
return set.contains(u);
}
The benefit of the first approach the ability for example to delete a user with all of its passwords (if there are multiple password possible), in O(#passwords).. As opposed to the other approach which gives encapsulation, but will cost iteration over all users to check if user.username == usernameSoughtAfter;
I have this code, and the string is coming from JSON from the server, and I use these if statements to prioritize what I want to get exported to the text file, but when I run it, the output isnt the output I am expecting, see below:
JSONObject attributeObject = objects.getJSONObject(objectAttribute);
String[] elementList = JSONObject.getNames(attributeObject);
for (String attributeName : elementList) {
if (attribute.equals("Custodian")){
String value = objects.getString("attributeValue");
System.out.print(value+",");
out.write(value);
out.append(",");
}
if (attribute.equals("Custodian Delegate")){
String value = objects.getString("attributeValue");
System.out.print(value+",");
out.write(value);
out.append(",");
}
if (attribute.equals("Authentication Directory")){
String value = objects.getString("attributeValue");
System.out.print(value+",");
out.write(value);
out.append(",");
}
if (attribute.equals("User ID")){
String value = objects.getString("attributeValue");
System.out.println(value);
out.write(value);
out.append(",");
out.newLine();
}
}
Expected output based from the if statements:
JDoe,CPer,Active Directory, No
But once I run it, the output becomes:
Active Directory,JDoe,CPer,No
Is there an easier way to fix this? My only problem is that the Authentication Directory goes first when I start running the program. Any tips? I would greatly appreciate.
Thanks in advance
make your life easy by creating a Model class
class Model{
String JDoe=""; //this is an example, so change attribute names using naming convention
String CPer="";
String Active_Directory="";
String No="";
#Override
public String toString(){
return JDoe+", " +CPer+", " +Active_Directory+", " + No;
}
}
now change your code to use this model, and only update the class Model without writing anything to the file.
for example:
Model model = new Model();
...
for(whatever condition is){ //start of the loop
if (attribute.equals("Custodian")){
String value = objects.getString("attributeValue");
model.CPer=value;
//System.out.print(value+",");
//out.write(value); <-- skip this
//out.append(","); <-- skip this
}
...
}
//after the loop
out.write(model.toString());
NOTE:
if you have two loops place Model model = new Model();
inside your outter loop
The output might be correct. You are iterating over all keys of the JSON-object. The resulting order does not depend on the order of your if-satements. In every loop only a single if-condition matches. The given snippet will output the elements in the same order as in the returned array.
The .getNames() returnes the array of the field names of the given Object. Then you are iterating over theses field names. Therfore the attribute value will have the same value per cycle. It is impossible that two if-condition will match because attribute can not equal for example "Custodian" and "Custodian Delegate" at thes same time.
It seems like the array contains the attributes in an alphabetic order. Therefore the attributeName-variable is "Authentication Directory" during the first cycle.
I am currently using a hashmap to store information about a Current Account.
Here is what I have in one method:
HashMap<String, Account> account = new HashMap<String, Account>();
if (Account.validateID(accountID)) {
System.out.println("Account ID added");
Account a = new Account(cl,accountID, sortCode, 0);
account.put(accountID, a); //add to HashMap
}
This seems to work fine. Then in another method I have:
public void enterTransaction()
{
String tAccountID = JOptionPane.showInputDialog(this,
"Enter valid accountID", "Add Account", 0);
System.out.println("Check if accountID exists: " + account.containsKey(tAccountID)); //testing if accountID exists - currently not working
Date currentDate = new Date();
System.out.println("Date and time of transaction: " + currentDate); //prints the date and time of transaction
}
Basically, i'm trying to make it so that when I go to enter a transaction, it checks that the AccountID that is entered for the transaction is equal to the AccountID from the HashMap (the key).
I tried using line 6 of the enterTransaction() to check whether it exists. However, it doesn't seem to work and always says "false" even when I know i have typed in the same accountID both times. I have also tried using this statement:
System.out.println(account.get(accountID));
This seems to give me "Account#cb1edc" ?
Sorry about the long question, it's a simple question really just thought i'd give you all the information I could. Thanks.
That is the correct behavior.
account.get(accountID) returns an Account object, which is being printed from the JVM memory dump.
To get some legible output, the Account class needs a toString method that returns a String with useful information.
When you try to print an object to the console, the JVM automatically searches for a toString method and uses that to stringify the object (make it humanly readable), if it cant find that method for the object it prints out the JVM's internal memory id for that object which looks a bit like garbage. Try this:
public String toString() {
return "This is account " + this.id; // or something like this
}