Java n00b question: is there any good way to do this?



  • Asking here because I don't like Stackoverflow and their silly rules.

    So, a very simplified version of my problem:

    I have a class Address and a List<Address> that I get from a library (can't touch their code). I need to write a optimization algorithm to find the best way to move stuff between Addresses. Something that in theory would look like this:

    class Car{
       public Address origin;
       public Address destination;
       public int capacity;
       //other variables
    }
    
    class Solution { //I'll need to generate many instances of this
        static List<Address> addresses; //the list is shared globally in the entire program and never changes, so I just made it a static variable
        List<Car> cars;
    
        int getSolutionScore(){
            ...
        }
    }
    

    BUT, I also need to store some information, specific to each Solution, about each Address (to avoid recalculating it every time). For example a list of Cars that visit it, and an integer indicating the score it contributes to the solution. So currently I'm using a separate "AddressInfo" class to store this extra information, and keeping a list of instances in the Solution, such that each instance corresponds to the Address instance with the same index.

    1. Is there any better solution I'm missing? There's no way to use subclasses or anything, right? Or I could use a Map< Address, AddressInfo>, but I don't see any significant advantage on that.
    2. In a setup like that (objects containing 2 or 3 lists of other objects), how do I make those inner objects reference each other?
    • If I store the list indexes, aside from it seeming "semantically wrong", it means I can't access properties of Address from inside the Car, which should be OK IMO since the objects can't exist without each other. I'd have to request them to the parent, which means now I have to store a reference to the parent too.
    • But if I store actual references, how the hell do I make a deep copy of the whole thing?

    Only way I can think is to store both, but now I have to pass twice as many objects around to create anything.



  • @anonymous234 said:

    There's no way to use subclasses or anything, right?

    Why can't you subclass it?



  • Because I get a list of already instantiated objects.



  • Well, right, but you can write a quick and dirty helper to convert them into your subclassed object.

    I dunno Java, I guess what I'm saying is to me the most obvious solution here is to subclass the library's addresses and add what you need to them.



  • Regarding the relationship between the scoring (to follow the existing example) and the Address objects, my first thought was to subclass Address to annotate the class with a score member variable.

    class ScoredAddress extends Address {
        private Score score;    // I don't want make any assumptions about the implementation of the score values
    
        public getScore() { 
            return score;
        }
    

    }

    This is just my first idea, and I can already see some problems with it, especially since Address is sacred. I'll have to give this some additional thought, but in the meanwhile I have some questions that I hope will help elucidate a solution:

    • Do you need to have the same (little-i) interface for several classes similar to Address? If so, does the scoring mechanism differ between them, and do you think it would make sense to have an Interface to abstract the interface?
    • Do you need to be able to look an Address given a Car, or a Car given an Address, or both, or neither?
    • Do you need to look up an Address's score given an Address? Given a Car? Do you need to look up a Car given an address-score pair, or either part of such a pair?
    • How frequently are you accessing the Addresses? Scores? Cars?
    • Do any or all of these elements need to persist?

    I may have some more questions in a little while. Also, I would start to look at some design patterns that might fit the problem, starting with the [Handle-Body](http://c2.com/cgi/wiki?HandleBodyPattern} family (especially Bridge).



  • Why can't you just have AddressInfo keep a reference to the address?

    Subclassing works too, but I personally find the containment a cleaner solution. AddressWithACar has-an address, not is-an address.



  • You know, after typing all that I'm starting to think I just overthought the whole thing. AdressInfo works just fine, and I'll just have to put all the logic in the parent, make Car and AddressInfo dumb structures, and pass indexes around.

    But to answer your questions

    Do you need to have the same (little-i) interface for several classes similar to Address?

    Thankfully, no :-P

    Do you need to be able to look an Address given a Car, or a Car given an Address, or both, or neither?
    Do you need to look up an Address's score given an Address? Given a Car? Do you need to look up a Car given an address-score pair, or either part of such a pair?

    I need an n-to-m relationship between Cars and Address(Infos), and a 1-to-1 relationship between Address and AddressInfos.

    Since I can't touch Address, I'll just do this:

    @Maciejasjmj said:

    Why can't you just have AddressInfo keep a reference to the address?

    And reference AddressInfos from the Car (or vector indexes and let the parent decide).

    How frequently are you accessing the Addresses? Scores? Cars?
    Do any or all of these elements need to persist?

    Scores and Cars, all the time, Address, actually not much since I precalculate all the distances between them at the beginning.


    Why can't Java come with a mini relational database? Car c = solution.query("SELECT FROM Cars WHERE origin=", this)



  • @anonymous234 said:

    Why can't Java come with a mini relational database? Car c = solution.query("SELECT FROM Cars WHERE origin=", this)

    Why don't you use C#, which has exactly that?



  • Sadly I don't get to pick the language.



  • Paging TopMind... actually, that's a really good question, especially sine (as @blakeyrat points out) C# has exactly that.



  • @anonymous234 said:

    Why can't Java come with a mini relational database?

    There are plenty of memory databases for Java.

    Also, write a wrapper around Address or map its data to a class you can control.



  • Given your apparent options, I think I'd create a class where the Address is a property:

       class ScoreAddress
       {
           private Address address;
           private int score;
           public ScoreAddress(Address address, int score)
           {
                this.address = address;
                this.score = score;
           }
           public Address getAddress() { return address; }
           public int getScore()    { return score; }
       }
    

    Then in your scoring loop you don't worry about the List index, you just tell each ScoreAddress which Address it contains:

       static List<ScoreAddress> car;
    
       for (Address a : addresses) {
           car.add(new ScoreAddress(a, getSolutionScore(a));
       }
    

    To read them out of your new list:

       int score;
       String city;
       for (ScoreAddress sc : car) {
           score = sc.getScore();
           city  = sc.getAddress().getCity();
       }
    

    No indexes needed.


  • Java Dev

    @anonymous234 said:

    Why can't Java come with a mini relational database? Car c = solution.query("SELECT FROM Cars WHERE origin=", this)

    If you're on java 1.8, you should be able to use streams https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

    cars.stream().filter(c -> c.getOrigin() == '')



  • You mean like

    addresses.stream().filter(a -> a.getOrigin() == "whatever");
    

    Granted, this is new in Java 8 and it assumes that your Address class has a .getOrigin method.

    Edit: @PleegWat beat me to it.



  • OK, but if I have two (or more) lists of objects referencing each other, how do I make a new copy of the whole thing?

    Something like this? Not worth it for my current case.

    @PleegWat said:

    If you're on java 1.8, you should be able to use streams https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

    cars.stream().filter(c -> c.getOrigin() == '')


    That's pretty cool. Still, my main objective was to eliminate all loops when accessing objects, for efficiency.



  • @anonymous234 said:

    That's pretty cool. Still, my main objective was to eliminate all loops when accessing objects, for efficiency.

    Yeeeeeaaah, there's no way to do a filter / WHERE clause without either an implicit or explicit loop. Sure, the database1 / framework may be hiding it from you, but it's still there.

    1The database may be checking its indexes instead of doing a full table scan depending on if the column you're filtering on is indexed or not.



  • @ScholRLEA said:

    Paging TopMind

    NO!

    NO!

    NOOOOOOOO!!!!!!



  • @anonymous234 said:

    Still, my main objective was to eliminate all loops when accessing objects, for efficiency.

    Even SQL proper can't do that. It can make the loops real fast, if you pick the correct indexes.



  • @anonymous234 said:

    OK, but if I have two (or more) lists of objects referencing each other, how do I make a new copy of the whole thing?

    Perhaps I misunderstood your problem. As I understood it, the problem was to build a list of solutions, that would be used later, and you needed to be able to associate each solution to the Address in the original list.

    My proposal makes each address a part of the combined solution (address + score) so, based on your problem, the original list shouldn't even be needed anymore. Just use the addresses that are part of your solution score.
    @anonymous234 said:

    Something like this? Not worth it for my current case.

    There's no need to pair them; you have all the addresses in the new "car" list in my example; a pointer to each. You should be able to do all your processing from the new list and unless you have some other use for the first list, you could even drop the reference to it.

    Remember that the Addresses are not "in that List": the List contains pointers to the Address instances. The new List in my proposal contains pointers to ScoreAddresses, but each of those objects in turn has a pointer to an Address. So you could "drop" the original List, and it wouldn't affect the new List or the Addresses to which it (indirectly) points.



  • I think you missed how Cars work. A Car visits many Addresses, an Address is visited by many Cars. That's my current problem, an n:m relationship.

    Yes, I have to store additional information for each Address (which is, if I understood correctly, what you called ScoreAddress, and I called AddressInfo), that part is solved now.



  • Is it bad that one of my major thoughts here was "stuff it in a database and make JPA @Entity classes for them" ?


  • Discourse touched me in a no-no place

    @anonymous234 said:

    Still, my main objective was to eliminate all loops when accessing objects, for efficiency.

    Doing something for all members of a collection of things is one of the canonical cases for a loop. It's the inner loops that you want to avoid…


Log in to reply