Can JUNG library make edges based on predefined properties? - java

I have some data of let’s say type Person. This Person has a phone-number property but also a calling and a called phone-number properties.
class Person {
String id;
String displayName;
String phoneNr;
String callingNr; // or List<String> callingNrs;
String calledNr; // or List<String> calledNrs;
}
What I want, is I put a bunch of those Person objects in a Graph instance and than render the relationships on a view. Ideally the components drawn on the view are interactive, meaning you can click on a node/vertex that highlight the edges (and maybe more).
I tried JUNG, but in the documentation, I see some examples that I have to, kind of, define the relationships between Person objects myself, like below:
Graph.addEdge("edge-name", personA.phoneNr, personB.phoneNr);
I’m new to JUNG, but maybe there’s a way to tell JUNG about the properties of Person and that JUNG knows how to connect them?
Is this possible with JUNG? Or do I need another type of library, if yes, than can someone please provide me one I can use?

Here is what I would do:
Make a java.util.Map of each person's phone number (key) to an instance of the Person (value). That is your reverse number lookup.
Populate your reverse number lookup map by iterating over your collection of people using the PhoneNr as the key and the Person instance as the value.
Next, I would create an edge class 'PhoneCall' that contains information like 'time of call' and 'duration of call' (more or less info, depending on what you have available).
To add edges to your graph, iterate over your collection of Person instances, and for each Person, iterate over the collection of calling numbers. For each calling number, use the reverse number lookup map to get the person calling and make a directed edge to connect the calling person to the current person.
Do something similar for the each Person's collection of called numbers.
Your graph nodes will be Person instances, and your edges will be PhoneCall instances that connect one Person to another. Be sure to add an equals and hashCode method to your Person class and to your PhoneCall class so that they will work properly (and duplicates will be detected and hopefully ignored).
Hope this helps!

Related

is it possible to create a hash map where each value is a method that acts differently on an object

Problem
I want to know if this is possible if I could create a State machine that would contain all the methods and the Values of MethodById would be stated in the machine.
P.S. this is my first question ever on here. If I do it wrong I'm sorry but that is why.
Description (TL;DR)
I'm trying to cross reference data about Sales representatives. Each rep has territories specified by zip-codes.
One dataset has the reps, their territories and their company.
Another data set has their names, phone number and email.
I made a Sales-rep class that takes from the first data-set and needs to be updated with the second data-set.
I also need the Sales-reps to be put in a look-up table (I used a hashmap for this) of <key: zip code, value: Sales-rep object>.
What I want is for each Sales-rep object to having an ID that is standard across all my datasets. I can't use the data I'm provided with because it comes from many different sources and its impossible to standardize any data field.
Names, for example, are listed so many different ways it would be impossible to reconcile them and use that as an ID.
If I can get an ID like this (something like an SSN but less sensitive) then I want to try what my question is about.
I want to iterate through all the elements in my <key: zip code, value: Sales-rep object> hashmap, we will call it RepsByZipCode. When I iterate through each Salesrep object I want to get an ID that I can use in a different hashmap called MethodById <key: ID, value: a method run on the Object with this ID>.
I want it to run a different method for each key on the Object with the matching key (AKA the ID). The point is to run a different method on each different object in linear time so that by the end of the for loop, each object in RepsByZipCode will have some method run on it that can update information (thus completing the cross-referencing).
This also makes the code very extendable because I can change the method for each key if I want to update things differently. Ex:
//SalesRep Object Constructor:
SalesRep(String name, String email, ..., String Id)
Map<String zipcode, Salesrep rep> RepsByZipCode = new HashMap<>{}
//code fills in the above with the first dataset
Map<String ID, ??? method> MethodById = new HashMap<>{}
//code fills in the above with the second dataset
for(String ZipKey:RepsByZipCode){
Salesrep Rep = RepsByZipCode.get(ZipKey);
Rep.getId = ID;
MethodById.get(ID);
//each time this runs, one entry in RepsByZipCode is updated with one
//method from MethodById.
//after this for loop, all of RepsByZipCode has been updated in linear time
You could put these methods into different classes that implement a common interface, and store an instance of each class in your map. If you're using at least Java 8 and your methods are simple enough, you could use lambdas to avoid some boilerplate.

Java - store name field by using hashmap vs using seperate class

If I need to capture the name (first, middle and last) of a Person, I thought of the following possibilities:
Use a Map<String, String> name;
Use a separate Name class.
If I use a Map, I can store the names like this:
name.put("first", "xyz")
name.put("middle", "abc")
name.put("last", "nhf");
Then in the Person class:
class Person
{
Map<String, String> name;
//below write setter and getter for it.
}
If I use a Name class, I can store like this:
class Name
{
String first;
String middle;
String last;
//Below write setters and getters for them.
}
Then in the Person class:
class Person
{
Name name;
//below write setter and getter for it.
}
I wanted to know which one is a better way of doing and why. Also if there is any other better way of doing this.
Maps are great for flexibility. I.e., if you don't know exactly what keys you're going to have. E.g., if one person will have a Christian name, another will have a nickname and a third will have a paternal and maternal surnames, a Map may make sense. In your example, everybody has a first, middle and last name (although some of them may possibly be null?), so a map just adds redundant complication (as as noted here on the thread, memory consumption). Frankly, unless you have some special use for the entire Name as an object (e.g., using it as a key in a map), I'd just place three string members directly in the Person class.
This is entirely up to you -- there is no "best" answer here. It depends on how you are using the class.
Generally you do not want to hide things in a map like that. It makes more work to ensure things are correct. What if you accidentally add an incorrect key to the map? Your data structures could get out of whack easily with that method.
Personally, I would most likely just have the 3 values on the Person class directly and not bother with a Name class or a Map.
Once again, I am using words like "most likely" and "generally" because I do not know how the class is being used.
Creating a map is quite memory consuming, compared to creating a name class.
It's better to create the name class, (for one thing, less lines of code :P), mainly because it's less prone to be changed mid-run, unlike the map.
The entries in a map might be accidentally changed during runtime, which could cause problems. If the Name class doesn't have setters, then this can't happen.

Making a java phone book using the link list data structure?

I got an assignment in which I have to make a phone book using a link list.
In this list I got to be able to add an entry. The entry must have a person first name,last name and phone number.
I have to be able to delete the first,last, and phone number of the entries.
How can I do this I am think of creating a class named entry with string for first,last,and phone number.
And when the user decides to create a new Record put a new Object entry with these fields. Into the link list.
The problem is how can I create a new Object and name it when the user want to put it on the list.
I cannot keep using the same name for an object over and over or can I?
You can't.
Suppose you have a class, Person, with properties as you suggested. directory is an object of type LinkedList<Person>. The correct way to do what you are trying to do is to make Person immutable. Every time you want to add a Person, you write statements such as directory.add(new Person("George", "Washington", "1776")) (the constructor initializes final Strings.
You must make new objects because LinkedList only stores references to objects, not copies of them.
Really, though, you can instead of Person use an associative array, for example mapping enum types for properties to strings.
Make a list of some kind (array, ArrayList, whatever floats your boat) and store it there using new Record(...).
Making a class for keeping the data is a good way to solve the problem.

How to dynamically create Lists in java?

I'm programming in java for a class project.
In my project I have airplanes, airports and passengers.
The passenger destination airport is randomly created, but then I have to add it to a List with passengers for that destination.
As long as the airports are read from a file thus they can vary, how can I create Lists according to these airports?
What I want to do is something like:
List<Passenger> passengersToJFK = new ArrayList<Passenger>();
.
.
.
if(passenger.destination == "JFK"){
passengersToJFK.add(passenger);
}
The problem is that as I've said, the number and name of airports can vary, so how can I do a general expression that creates Lists according to the Airports File and then adds passengers to those Lists according to the passenger destination airport?
I can get the number of Airports read from the file and create the same number of Lists, but then how do I give different names to this Lists?
Thanks in advance
You can keep a registry of the associations between a destination or airport and a list of passengers with a Map, in a particular class that centers this passengers management.
Map<String,List<Passenger>> flights = new HashMap<String,List<Passenger>>();
Then, whenever you want to add a new destination you put a new empty list and
public void addDestination(String newDestination) {
flights.put(newDestination, new ArrayList<Passenger>());
}
When you want to add a passenger, you obtain the passenger list based on the destination represented by a String.
public void addPassengerToDestination(String destination, Passenger passenger) {
if(flights.containsKey(destination))
flights.get(destination).add(passenger);
}
I suggest you dig a little deeper into some particular multi-purpose Java classes, such as Lists, Maps and Sets.
I would probably create a Map of airports with airport name as the key and a List of passengers as the value.
e.g.
Map<String, List<String>> airports = new HashMap<String, List<String>>();
airports.put("JFK", passengersToJFK);
You sound like you're thinking too much in terms of primitives, Strings, and collections and not enough in terms of objects.
Java's an object-oriented language; start thinking about Objects and encapsulation.
You've got a good start with your Passenger class. Keep going with Airport.
Do you add Passengers to Airport? Nope, I think they belong to a Flight.
Do a little thinking about your problem before you write more code.
You shouldn't focus on giving the actual variables of list objects unique names, but instead, create a map from String (destination id) to List (passengers heading to that destination), and add lists on the fly to that map, linking each new list to its relevant destination. Update the lists in that map as needed.
The best way to do it is to create objects for all three.
You might have an Airport object that looks like this:
class Airport{
String name;
List Airplane airplanes;
}
then you would have an airplane that looked like this:
class Airplane{
String name; // ?? or bodyType? or whatever else you need
List Passenger passengers;
}
In this way you compose your objects from each other in a way that ends up being much easier to understand and deal with.
Note that I'm leaving off methods, like Airport probably has a method like "addAirplane" to add another airplane, and the airplane object has an addPassenger method...

Java collection for this use case

Let's say we have a bunch of Car objects.
Each Car has some distinguishing properties e.g. manufacturer, model, year, etc. (these can be used to create distinct hashCodes).
Each car has a List of PurchaseOffer objects (a PurchaseOffer object contains pricing\retailer info).
We receive Lists of Cars from several different sources, each Car with a single PurchaseOffer.
Thing is, these lists may overlap - a Car can appear in more than one list.
We wish to aggregate the lists into a single collection of Cars where each Car holds all encountered PurchaseOffers for it.
My Problem is choosing what to collection to use in this aggregation process:
Feels natural to use java.util.HashSet for holding our cars, that way when going over the different lists of Cars, we can check if a car already exists in the Set in amortized O(1),
however - you cannot retrieve an element from a Set (in our case - when we go encounter a Car that already exists in the Set - we would have liked to retrieve that Car from the Set based on its identifying hashCode and add PurchaseOffers to it).
I can use a HashMap where each Car's hashCode maps to the actual Car object, but it probably isn't the school-book solution since it is unsafe - I would have to make sure myself that every hashCode maps to a Car with that hashCode - there could be inconsistency.
Of course, can make a designated data structure that guarantees this consistency - Shouldn't one already exist ?
Can anyone suggest the data-structure I am after, or point out a design mistake ?
Thanks.
Since this is a many-to-many relationship, you need a bi-directional multi-map. Car is the key for the first one, with a List of PurchaseOrder as the value. The PurchaseOrder is the key for the second one, with a List of Cars as the value.
The underlying implementation is two HashMaps.
Put an API on top of it to get the behavior you need. Or see if Google Collections can help you. It's a combination of a BiMap and two MultiMaps.
I think that you really do need (at least) a HashMap<Car, List<PurchaseOffer>> ... as suggested by #Andreas_D
Your objection that each Car already has a List<PurchaseOffer> is beside the point. The list in the HashMap is the aggregate list, containing all PurchaseOffer objects from all Car objects that stand for the same physical car.
The point of creating a new list is to avoid changing the original lists on the original Car objects. (If that was not a concern, then you could pick one instance of Car from the set that represent a physical car, and merge the PurchaseOffer objects from the others into that list.)
I'm not entirely sure why #duffymo suggested a bi-directional map between, but I think it is because the different Car objects from different sources may have complementary (or contradictory) information for the same physical car. By keeping all instances, you avoid discarding information. (Once again, if you are happy to discard mutate and/or discard information, you could attempt to merge the information about each individual car into a single Car object.
If you really didn't care about preserving information and were prepared to merge stuff willy-nilly then the following approach would probably work:
HashMap<Car, Car> map = new HashMap<Car, Car>(...);
for (Car car : carsToBeAggregated) {
Car master = nap.get(car);
if (master == null) {
map.put(car, car);
} else {
master.offers.addAll(car.offers);
// optionally, merge other Car information from car to master
}
}
You should NOT be trying to use the Car.hashCode() as a key for anything. Hashcode values are not unique identifiers: there is a distinct possibility that two different cars will end up with the same hashcode value. If you attempt to use them as if they were unique identifiers you'll get into trouble ...
The basic datastructure should be a HashMap<Car, List<PurchaseOffer>>. This allows for storing and receiving all offers for one selected car.
Now you may have to find a suitable implementation for Car.equals() to assure, that "cars" coming from different source are really the same. What about basing equals() on a unique identifier for a real world car (VIN)?
I would prefer to use a HashMap<Car, List<PurchaseOffer>>, as suggested before (Andreas, Stephen), mainly if the Car object does not hold the list of PurchaseOffers.
Otherwise I would consider using a HashMap<Car, Car> or, better IMO, a HashMap<ID, Car> if there is an unique ID for each Car.
It can not simply map the Car's hashCode to the Car, as mentioned in the question, since distinct Cars can have the same hashCode!
(Anyway, I would create an own class for storing and managing the Cars. This would contain the HashMap, or whichever - so it's easy to change the implementation without needing to change its interface)
create tout custom class that extends hash
Set, override method contains(Object o) check there os hash code is same or not and return result according, and add object to set of and only if it not containing that object
How about a defining a new custom Aggregation class? Define the hashcode such that the id of the car acts as the key and override the equals() accordingly. Define a custom method for accepting your original car and do a union operation on the lists. Finally store the custom objects in a HashSet for achieving constant time look up.
In purist terms, aggregation is a behavior beyond the scope of a single object. Visitor pattern tries to address a similar problem.
Alternatively if you have a sql datastore, a simple select using group by would do the trick.
Welp, yeah, HashMap<Car, List<PurchaseOffer>> would be perfect if it wasn't for the fact that
each Car contains a List<PurchaseOffer> as a property. Can say that a Car object is composed
of two parts: an identifying part (let's say each car indeed has a unique VIN), and the list of
PurchaseOffers.
In this case split the Car class in two classes - the CarType class with the identifying attributes, and then the list part (maybe both together used by Car). Then use Map<CarType, Lost<PurchaseOffer> for your datastructure (or MultiMap<CarType, PurchaseOffer>).
//alt. 1
List<Offer> offers;
List<Car> cars;
Map<Car, List<Offer>> mapCarToOffers;
Map<Offer, List<Car>> mapOfferToCars;
public void List<Offer> getOffersForCar(Car aCar);
public void List<Car> getCarsForOffer(Offer anOffer);
Alternative 1 would make use of the hashCode() of Car and Offer
//alt. 2
List<Offer> offers;
List<Car> cars;
Map<Integer, List<Offer>> mapCarIdToOffers;
Map<Integer, List<Car>> mapOfferIdToCars;
public void List<Offer> getOffersForCarId(int aCarId);
public void List<Car> getCarsForOfferId(int anOfferId);
Alternative 2 would make use of the hashCode() of Integer. This would allay your concerns about "safety" as the hash codes for Integer objects should not overlap where the values are unique. This incurs the additional overhead of having to maintain unique IDs for each Car and Offer object, however, I am guessing that you probably already have those from your business requirements.
Note, you may choose to use other classes as alternative to ints for ID's (e.g. String).
For both alternatives, implement the Lists with ArrayList or LinkedList - which one is better is up to you to determine based on other requirements, such as the frequency of insertion/deletion vs lookup. Implement the Maps with HashMap - see comments above about how hash codes are used.
As a side note, in our software, we use these both of the above to represent similar types of many-to-many data. Very similar to your use case.
Both alternatives work very well.
Why not use an object database for this? You could store any object graph you wanted, and you'd get a search API with which you could do any relationship/retrieval mechanism you wanted. A simple collection could work, but it sounds like you want a more complex relationship than a collection would provide. Look into db4o (http://db4o.com) - it's very powerful for this sort of thing.

Categories