Is an Array of Arrays the right thing to do here? - java

My goal here is get an object that I can iterate over and grab my User's firstName and his favColor.
I have this:
for (Map user : userListing){
String firstName = (String) user.get(User.FIRST_NAME);
String favColor = (String) user.get(User.FAVORITE_COLOR);
// Build up some Arrayish object add "Bob", "red"
//
// what do i do here?
}
I'm unsure if I need to create, say an Array of Arrays?
My thought is that way I know the outer level of the Array is representative of each User, then once I'm the next level deep, item[0] would be the first name and item[1] would be the color.

I'm not sure what would be the best solution here. Using a Map to represent an user is already wrong in first place. I'd create a javabean class which represents an User.
public class User {
private String firstName;
private String favoriteColor;
public String getFirstName() {
return firstName;
}
public String getFavoriteColor() {
return favoriteColor;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setFavoriteColor(String favoriteColor) {
this.favoriteColor = favoriteColor;
}
// Add if necessary other javabean boilerplate like Serializable,
// default c'tor, full c'tor, equals(), hashCode(), toString().
}
Then just collect them in a List<User> and pass that around instead.

Two ways to do it that are pretty simple
Map<String,Map<String,Double>> map2d = new HashMap<String,Map<String,Double>>();
For each new "x-coordinate", you'd have to instantiate
a new sub-HashMap, and put it into map2d. This could all be
wrapped in some new class.
to retrieve an element, you just use:
map2d.get(xKey).get(yKey)
Create a pair type and use that as your map key
http://www.velocityreviews.com/forums/t390520-2d-lookup-table.html

I would recommend:
create a java bean like object:
class Preferences{
//properties
//getters
//setters
}
then have a array of Preferences
Preferences[] userPrefs = new Preferences[N]
iterate by for (Preferences p : userPrefs) { //do the stuff}

Related

Searching an ArrayList for a matching parameter

I have two classes Museum and Painting. Painting class is working as expected, but I am having issues with the Museum class. The purpose of the method is to return an ArrayList of paintings the museum has, which matches the parameter string.
When I try to compile the code, I am getting lots of error messages and clearly I am not compiling the code correctly.
For example, if there is a Painting by Picasso - it should just return all those paintings and nothing else.
I think I may have missed a step - potentially by creating a local variable to store it in first, but I'm at a bit of a brick wall. I also wonder if String is correct when the ArrayList uses the Painting object.
Does anyone know what I'm missing here?
public class Museum {
//creating the fields
private ArrayList<Painting> paintings;
private String name;
/**
* Create a Museum Class
*/
public Museum(String aMuseum) {
paintings = new ArrayList<>();
name = aMuseum;
}
public String listMatches(String searchString)
{
if(filename.equals(searchString)) {
return filename;
}
}
}
Searching paintings by artist should return a sublist of paintings (it may be empty if no painting is found):
public List<Painting> listMatches(String artist) {
List<Painting> matches = new ArrayList<>();
for (Painting painting : paintings) {
if (artist.equals(painting.getArtist())) {
matches.add(painting);
}
}
return matches;
}
Stream API may be used for this (more concise and functional style):
public List<Painting> listMatches(String artist) {
return paintings.stream()
.filter(p -> artist.equals(p.getArtist()))
.collect(Collectors.toList());
}
Okay I'm assuming here in your Painting class, you have an attribute which is Author and a getter for it.
I've changed the listMatches method to have a for-each loop. This loop will go through every element in your Paintings arraylist, and saving in a local variable the name of its author. If the current painting's author matches the one you are looking for, it will print the title.
I changed the return type of listMatches from String to void, because you are not returning anything, just printing.
Instead of just printing the names you could save the paintings somewhere (another ArrayList for example) if you want to use them. Remember to change the return type, because in that case you will be returning something.
Remember to write the name of the author exactly as you have it in the paintings or else it might not find it.
I havent had a chance to try it, but it should work.
public class Museum {
//creating the fields
private ArrayList<Painting> paintings;
private String name;
/**
* Create a Museum Class
*/
public Museum(String aMuseum) {
paintings = new ArrayList<>();
name = aMuseum;
}
public void listMatches(String searchString)
{
String this_painting_author = new String();
for (Painting painting : paintings){
this_painting_author = painting.getAuthor();
if(this_painting_author.equals(searchString)) {
System.out.println(painting.getTitle());
}
}
}
}

What JavaFX data structure should I use in the following example?

I have the following class GroupStudentsBySurname and it contains the following data structure HashMap<String, ArrayList<Student>>.
Each Student object contains two attributes: surname and english_score
The keys are the surname of students taken from the Student object Student.surname. For a particular key Lee, it has an ArrayList<Student> where the Students share the same surname.
One of the method of this GroupStudentsBySurname class is to compute the average_english_score for Students having the same surname.
I would use a TableView data structure for the class GroupStudentsBySurname, which looks like the following:
Surname | average_english_score <- column headings
Lee | 65
Chan | 86
Smith | 76
I want to be able to use track the changes of class GroupStudentsBySurname every time I add/delete a Student object from the arraylist, which in turn affects the average_english_score attribute.
Question: I do not know what data structure from javafx I should use in this case? Would I need to use ObservableMap or ObservableList to track the changes whenever I add / delete a Student object.
JavaFX is a UI technology, so not entirely sure what you mean be 'data structure from JavaFX'.
Anyway, let's start with the data model (we'll get to the UI later).
First I think you need to introduce another class (which requires a valid implementation of equals and hashCode on Student):
public class StudentGroup
{
private Set<Student> students = new HashSet<>();
private BigDecimal englishTotal = BigDecimal.ZERO;
public BigDecimal getEnglishAverage()
{
return englishTotal.divide(students.size());
}
public Collection<Student> getStudents()
{
return Collections.unmodifiableCollection(students);
}
public void addStudent(Student student)
{
if (students.add(student))
{
englishTotal.add(student.getEnglishScore());
}
}
public void removeStudent(Student student)
{
if (students.remove(student))
{
englishTotal.subtract(student.getEnglishScore());
}
}
}
Your class GroupStudentsBySurname then becomes:
public class GroupStudentsBySurname
{
private Map<String, StudentGroup> students = new HashMap<>();
...
}
Then create an adapter row class, which will allow StudentGroup to be used in more grouping scenarios than just being grouped by surname and is what will be used with JavaFX:
public class StudentBySurnameRow
{
private SimpleStringProperty surname;
private SimpleStringProperty groupSize;
private SimpleStringProperty englishAverage;
public StudentBySurnameRow(String surname, StudentGroup studentGroup)
{
this.surname = new SimpleStringProperty(surname);
this.groupSize = new SimpleStringProperty(Integer.toString(studentGroup.getStudents().size()));
this.englishAverage = new SimpleStringProperty(studentGroup.getEnglishAverage().toString());
}
...
}
Once you have these classes they can be slotted into a JavaFX TableView as per the Oracle TableView tutorial where you would create an ObservableList like this:
List<StudentBySurnameRow> studentBySurnameRows = new ArrayList<>();
for (Map.Entry<String, StudentGroup> entry : groupStudentsBySurname.getStudents().entrySet())
{
studentBySurnameRows.add(new StudentBySurnameRow(entry.getKey(), entry.getValue()));
}
table.setItems(FXCollections.observableArrayList(studentBySurnameRows));
I would use either a ListView or a TableView. In your case, if you just want to be able to manipulate the list, the first would be more practical. Otherwise, if you really want to use the whole map, the latter.

How to save an ArrayList in Play?

This might seem like a very basic question, but I have a model (User) which I want to store an ArrayList of Strings (they are the id's of other users). I declare the List like this:
public List<String> friends = new ArrayList<String>();
After I add an entry to the array, I save the user. But friends is always null when I try to use it. Is there a specific way to save an ArrayList? Any help would be appreciated.
My model:
#Entity
public class User extends Model {
#Id
public String username;
public String password;
public List<String> friends = new ArrayList<String>();
public static Finder<String, User> find = new Finder<String, User>(String.class, User.class);
// Constructor
public User(String username, String password){
this.username = username;
this.password = password;
}
// Methods
public void addFriend(String friend){
friends.add(friend);
}
// Static Methods
public static User authenticate(String username, String password){
return find.where().eq("username", username).eq("password", password).findUnique();
}
public static void befriend(String user1, String user2){
User.find.ref(user1).addFriend(user2));
User.find.ref(user2).addFriend(user1);
User.find.ref(user1).save();
User.find.ref(user2).save();
}
}
The controller method:
return ok(index.render(
User.find.byId(request().username()).friends,
));
And a very simple view:
#(friends: List[User])
<div id="current_friends">
#for(friend <- friends) {
#friend.username
}
</div>
You need to save the relations 'manually' with saveManyToManyAssociations(String fieldname), for an example:
public static void befriend(String userName1, String userName2){
User user1 = User.find.byId(userName1);
User user2 = User.find.byId(userName2);
user1.friends.add(user2);
user2.friends.add(user1);
user1.save();
user2.save();
// here...
user1.saveManyToManyAssociations("friends");
user2.saveManyToManyAssociations("friends");
}
(note: written from top of my had so debug it yourself pls)
One potential reason for this problem could be your view:
The first line of your view is
#(friends: List[User])
The User does not have a package name, which could cause the null pointer exception.
In my case, my User bean is under models package, so I have the following line:
#(friends: List[models.User])
I encountered the exact same problem, and here is how I fixed it (with a little explanation coming along).
In fact, you try to save an ArrayList (thus something which size is undefined) in a DataBase. And apparently (and quite logically), the Play Framework doesn't really like it ; you have to use whether annotations or a transient class. I decided to use the class way (also because i don't know how to use the annotations to make a sub table, so I didn't took the risk, but it's not the best way to do it. In fact, it's an horrible way of doing it. But still, here it is).
In your case, you could to this :
#Entity
public class Friends extends Model {
#Id
public Long id;
#Required
public String user1;
#Required
public String user2;
public static Finder<Long, Friends> find = new Finder<Long, Friends>(Long.class, Friends.class);
//Here put your functions, I myself only added an insert method for the moment :
public static void add(String user1, String user2){
Friends f = new Friends();
f.user1 = user1;
f.user2 = user2;
bu.save();
}
}
And in your User model, just change the part in which you save both user into each other's List by this function.
Hope this will help.
Note : the id is here because I like numeric ids, feel free to change it.
Note 2 : Of course, it would be much better to use #ManyToOne and #OneToMany annotations, but as I wrote before, I don't know exactly how does it work.

Constructor takes two Integers and they must not equal, whats the best way to implement this?

public MyClass(Integer userId, Integer otherId) {
if(!userId.equals(otherId)){
this.userId = userId;
this.otherId = otherId;
}
}
Thats as far as I got, I want to ensure an instance if never created with matching id's ?
If you can't allow the two values to be equal then pretty much your only option it to raise an exception in that case.
I created another method and made the constructor private, it returns null if matching ids
private MyClass(Integer userId, Integer otherId) {
{
this.userId = userId;
this.otherId = otherId;
}
}
public static MyClass getInstance(Integer userId, Integer otherId)
if(!userId.equals(otherId)){
return new MyClass(userId,otherId);
}
return null;
}
I might be completely missing the point of your design, but if you want to create instances of an object with unique ID's that never clash consider using a UUID. Your instances should never have to do a 'circle-jerk' of ID comparisons to make sure none of them are violating the uniqueness constraints.
Documentation on UUID.
I use another approach, I keep a registry of newly created instances (in an HashSet) and allow instatiation of Objects via a static factory.
class User {
private int _id;
private static HashSet _instanced = new HashSet();
public static User getInstance(Integer id) {
if (_instanced.contains(id)) {
return null;
}
return new User(id);
}
private User(Integer id) {
_id = id.toInt();
}
// Getter/Setter for ID
}
Since the constructor is private, none will instantiate another User with the same id.
in your methods you could then write
User x = User.getInstance(1);
Of course this will add one more level to your solution. Still I prefer this kind of approach.

How can I serialize a list of objects using flex json?

I have a list of an object like follows
List<ProductInfo>
I want to serialize it using flex json so that it should like
[{"product_id":"2","name":'stack"'},{"product_id":"2","name":"overflow"}]"
for deserializing from the above string into a List of Objects I am using the following code
final List<ProductInformation> productInformationList = new JSONDeserializer<List<ProductInformation>>().use(null, ArrayList.class)
.use("values", ProductInformation.class).deserialize(parameterValue);
for serializing the object to string I am doing this but it's not working....I am missing something...
final String serializizedString = new JSONSerializer().serialize(productInformationList);
What do I need to serialize the object into a string?
List<ProductInfo> ls = new JSONDeserializer<ArrayList<ProductInfo>>().use("values", ProductInfo.class).deserialize(s);
Follow this link or read care fully following
Refactored path listings for Maps and Collections. In prior versions there was no way to specify both the concrete top of a Collection/Map AND the concrete class contained within. The path language was not verbose enough. Now you can specify both the concrete collection AND the concrete class contained within. if person.friends is a path that points to java.util.Map. For example,
new JSONDeserializer<Person>()
.use( "person.friends", HashMap.class )
.use("person.friends.keys", Relation.class )
.use( "person.friends.values", Person.class )
By adding "keys" and "values" to the path person.friends you can specify the actual concrete classes to use for the keys and values of the Map. For Collections you can simply append "values" to specify the containing class. For example:
new JSONDeserializer<List<Person>>().use( "people", ArrayList.class ).use("people.values", Person.class )
I've never played with flexjson before but after downloading it and playing with it here is what I've come up with:
public class TestFlexJson {
public static void main(String args[]) {
ProductInfo p1 = new ProductInfo(1, "Stack");
ProductInfo p2 = new ProductInfo(2, "Overflow");
List<ProductInfo> infos = Arrays.asList(p1, p2);
String s = new JSONSerializer()
.exclude("*.class", "description")
//.include("productId", "name")
// EDIT: the "include" call is irrelevant for this example.
.serialize(infos);
System.out.println(s);
// => [{"name":"Stack","productId":1},{"name":"Overflow","productId":2}]
List<ProductInfo> ls = new JSONDeserializer<List<ProductInfo>>().deserialize(s);
System.out.println(ls);
// => [{name=Stack, productId=1}, {name=Overflow, productId=2}]
}
public static class ProductInfo {
private int id;
private String name;
private String desc; // Not used, to demonstrate "exclude".
public ProductInfo(int id, String name) {
this.id = id;
this.name = name;
}
public int getProductId() { return this.id; }
public String getName() { return this.name; }
public String getDescription() { return this.desc; }
}
}
Seems to work for me.
Unfortunately, the class property must be included if you need to deserialize your json into a collection. In the above example, the json string was deserialized as follows:
List<ProductInfo> ls = new JSONDeserializer<List<ProductInfo>>().deserialize(s);
System.out.println(ls);
// => [{name=Stack, productId=1}, {name=Overflow, productId=2}]
If you were to try to access an element directly, lets say ls.get(0)y you would receive a ClassCastException: java.util.HashMap cannot be cast to ProductInfo.
You must serialize your object to include the class property in order to appropriately deserialize into a collection.

Categories