Merging and comparing two arrays - java

How do I compare each element in two different sets of data, and then merge certain elements of them into a new set of data?
Some info about my methods below. Note:
Not using java.lang.Collections
In one class I have these calls initializers:
BookCollection collection1 = new BookCollection(100);
BookCollection collection2 = new BookCollection(50);
BookCollection collection3 = new BookCollection(150);
And this call to my method merge(which I am trying to complete)
collection3.merge(collection1, collection2);
Anndd in another class my method merge is trying to compare the two sets of data(collection 1 and 2) and if it finds an elements that are equal, only add 1 of those elements to the new collection. Otherwise, add all of the non-equal elements to the new collection.
Here is what I made, but I know that it isn't working. There is a call to one of my other methods findBook that I will post.
public BookCollection merge(BookCollection c1,BookCollection c2){
//use this. operator to grab other vars
BookCollection cNew = new BookCollection(cNew);
for(String s1: c1)
if (s1.equals(c2)) {
cNew = c1;
}
cNew = c1 + s1;
}
Annddd
private int findBook(String isbn){
// iterate all the Book elements in the collection array
for(int i = 0; i <= collection.length; i++){
// check if the current book isbn matches the one provided argument
if (collection[i].getIsbn().equals(isbn))
return i;
}
return -1;
}

The solution should be far shorter than that.
I'll give you some tips because the idea is not give plain solutions and this question I'm pretty sure is homework.
If the question is homework add 'homework' tag
Tips:
Your main method doesn't have any loop. How are gonna iterate over the collections?
Books as objects they are should have an equals method. If that method is correctly implemented (you should define what is a method begin equals to another), then you just can compare b1.equals(b2)
Collections have contains method to check if it contains (by using equals) other book
Math.min method calculates the minimum between two integers or doubles (there are two versions)
Also, to be complete, if your collections are of a certain type your books should implement hashCode in a compatible way with equals (but my guess is you don't know what hashing is yet, and you'll not use that kind of collections)
So first of all: devise an algorithm. The simpler the better. In plain English.
Just then try to implement that. You'll see the code is much simpler and tidy if you try to program a previous well thought concept.
Edit:
Ensure to know what a Collection is in Java world (tip: is a general interface implemented by several distinct more specific classes).
And don't use the word array unless you are using real arrays (and given your exercise proposal it doesn't seem you need it).

Related

Does HashSet Provide Any Added Value to Performance in This Instance?

So, I'm working with an existing method in Java that returns a List (ArrayList). However, I want to add some functionality to it so that if specified, it will exclude a certain Object. Now I understand that in general using contains() on a HashSet yields better performance vs an ArrayList, but I'm wondering if there is a justifiable performance boost to be had in the two variations of the code I have below:
Notes: listOfAccounts is an ArrayList returned from a DAO call. personalAccount is an Object of type Account.
if (excludePersonalAccount) {
Set<Account> accounts = new HashSet<Account>(listOfAccounts);
if (accounts.contains(personalAccount) {
listOfAccounts.remove(personalAccount);
}
}
VS
if (excludePersonalAccount) {
listOfAccounts.remove(personalAccount)
}
Set<Account> accounts = new HashSet<Account>(listOfAccounts);
The above line takes all of the elements of the ArrayList and adds it to the HashSet. Instead of doing all of that, you could iterate over the List and look to see if your element is contained inside it. If it is, then you can remove it (which is essentially what you second snippet is doing).
For that reason, the second snippet is preferred, as they both run in linear time.

Java TreeSet Comparator

I have a Vehicle class with fields: baseVehicleId, subModelId, notes and partNo
If is the same baseVehicleId, subModelId and partNo , i want the object with the longest notes to remain( and delete the others)
I have this:
Comparator<Vehicle> comparator = new Comparator<Vehicle>() {
#Override
public int compare(Vehicle a, Vehicle b) {
if(a.baseVehicleId().equals(b.baseVehicleId()) && String.valueOf(a.subModelId ()).equals(String.valueOf(b.subModelId ()))
&& String.valueOf(a.partNo ()).equals(String.valueOf(b.partNo ()))
))
return a.getOurnotes().compareTo(b.getOurnotes());
// not good I know
return 1;
}
};
TreeSet<Vehicle> treeSet = new TreeSet<Vehicle>(comparator);
How can i modify this code :/?
So for example if i have all the fields equal and the length of notes are greater then delete the other objects.
The comparator's job is simply to say which of two objects comes first - there's no mechanism to manipulate the underlying collection during it's comparisons. I think you would want to think about this in a slightly different way: perform your filtering logic prior to adding an object to your collection.
I'd recommend just using a standard list, say ArrayList for sake of simplicity. Also you'd need to override the equals() method in your Vehicle class which returns true if two Vehicles share the same IDs and part numbers.
When it comes to adding new vehicles you can do something like this:
int vehicleIndex = myvehicles.indexOf(vehicle) // -1 if missing, otherwise 0 or greater to represent the index position
if (vehicleIndex == -1) {
// No item in the list shares the ids/model/part numbers so can add
myvehicles.add(vehicle)
} else {
// There's another similar vehicle, better compare their notes:
Vehicle existingVehicle = myvehicles.get(vehicleIndex); // retrieve the object from list so that we can compare it
// check if the new vehicle has longer notes
if (vehicle.getOurNotes().length > existingVehicle.getOurNotes().length) {
// if it does, remove the old one from the list
myvehicles.remove(vehicleIndex);
// and add the new one. Effectively we've done a replacement
myvehicles.add(vehicle)
}
}
Obviously it's not automatically sorted but you can do that after adding a batch of items by running the Collections.sort() method which also accepts a Comparator, but this time your comparator can focus on the specific task of detailing the ordering now that you know the list is pre-filtered so you are not concerned with trying to filter items out.
I think you should use the method
maximum = Collections.max(collection, comparator);
for searching the maximum of the elements and then just delete the others with
collection.remove();
Inside the comparator you can't delete from the collection.
Just loop through the collection and remove everything that doesn't meet your requirements using it.remove().
You may also want to look at the Java 8 collections functionality that will allow you to do things like filter a collection as that will also do what you are looking for.

What's more efficient and compact: A huge set of linkedlist variables or a two-dimensional arraylist containing each of these?

I want to create a large matrix (n by n) where each element corresponds to a LinkedList (of certain objects).
I can either
Create the n*n individual linked lists and name them with the help of eval() within a loop that iterates through both dimensions (or something similar), so that in the end I'll have LinkedList_1_1, LinkedList_1_2 etc. Each one has a unique variable name. Basically, skipping the matrix altogether.
Create an ArrayList of ArrayLists and then push into each element a linked list.
Please recommend me a method if I want to conserve time & space, and ease-of-access in my later code, when I want to reference individual LinkedLists. Ease-of-acess will be poor with Method 1, as I'll have to use eval whenever I want to access a particular linked list.
My gut-feeling tells me Method 2 is the best approach, but how exactly do I form my initializations?
As you know the sizes to start with, why don't you just use an array? Unfortunately Java generics prevents the array element itself from being a concrete generic type, but you can use a wildcard:
LinkedList<?>[][] lists = new LinkedList<?>[n][n];
Or slightly more efficient in memory, just a single array:
LinkedList<?>[] lists = new LinkedList<?>[n * n];
// Then for access...
lists[y * n + x] = ...;
Then you'd need to cast on each access - using #SuppressWarnings given that you know it will always work (assuming you encapsulate it appropriately). I'd put that in a single place:
#SuppressWarnings("unchecked")
private LinkedList<Foo> getList(int x, int y) {
if (lists[y][x] == null) {
lists[y][x] = new LinkedList<Foo>();
}
// Cast won't actually have any effect at execution time. It's
// just to tell the compiler we know what we're doing.
return (LinkedList<Foo>) lists[y][x];
}
Of course in both cases you'd then need to populate the arrays with empty linked lists if you needed to. (If several of the linked lists never end up having any nodes, you may wish to consider only populating them lazily.)
I would certainly not generate a class with hundreds of variables. It would make programmatic access to the lists very painful, and basically be a bad idea in any number of ways.

Java: How do I implement a method that takes 2 arrays and returns 2 arrays?

Okay, here is what I want to do:
I want to implement a crossover method for arrays.
It is supposed to take 2 arrays of same size and return two new arrays that are a kind of mix of the two input arrays.
as in [a,a,a,a] [b,b,b,b] ------> [a,a,b,b] [b,b,a,a].
Now I wonder what would be the suggested way to do that in Java, since I cannot return more than one value.
My ideas are:
- returning a Collection(or array) containing both new arrays.
I dont really like that one because it think would result in a harder to understand code.
- avoiding the need to return two results by calling the method for each case but only getting one of the results each time.
I dont like that one either, because there would be no natural order about which solution should be returned. This would need to be specified, though resulting in harder to understand code.
Plus, this will work only for this basic case, but I will want to shuffle the array before the crossover and reverse that afterwards. I cannot do the shuffling isolated from the crossover since I wont want to actually do the operation, instead I want to use the information about the permutation while doing the crossover, which will be a more efficient way I think.
My question is not about the algorithm itself, but about the way to put in in a method(concerning input and output) in Java
Following a suggestion from Bruce Eckel's book Thinking in Java, in my Java projects I frequently include some utility classes for wrapping groups of two or three objects. They are trivial and handy, specially for methods that must return several objects. For example:
public class Pair<TA,TB> {
public final TA a;
public final TB b;
/**
* factory method
*/
public static <TA,TB> Pair<TA,TB> createPair(TA a,TB b ){
return new Pair<TA,TB>(a,b);
}
/**
* private constructor - use instead factory method
*/
private Pair(final TA a, final TB b) {
this.a = a;
this.b = b;
}
public String toString() {
return "(" + a + ", " + b + ")";
}
}
Read the last section of this article:
http://www.yoda.arachsys.com/java/passing.html
To quote:
This is the real reason why pass by
reference is used in many cases - it
allows a method to effectively have
many return values. Java doesn't allow
multiple "real" return values, and it
doesn't allow pass by reference
semantics which would be used in other
single-return-value languages.
However, here are some techniques to
work around this:
If any of your return values are status codes that indicate success or
failure of the method, eliminate them
immediately. Replace them with
exception handling that throws an
exception if the method does not
complete successfully. The exception
is a more standard way of handling
error conditions, can be more
expressive, and eliminates one of your
return values.
Find related groups of return values, and encapsulate them into
objects that contain each piece of
information as fields. The classes for
these objects can be expanded to
encapsulate their behavior later, to
further improve the design of the
code. Each set of related return
values that you encapsulate into an
object removes return values from the
method by increasing the level of
abstraction of the method's interface.
For instance, instead of passing
co-ordinates X and Y by reference to
allow them to be returned, create a
mutable Point class, pass an object
reference by value, and update the
object's values within the method.
As a bonus, this section was updated by Jon Skeet :)
If it is reasonable for the caller to know the size of the returned arrays ahead of time, you could pass them into the method:
public void foo(Object[] inOne, Object[] inTwo, Object[] outOne, Object[] outTwo) {
//etc.
}
That being said, 90+% of the time multiple return values out of a method are hiding a better design. My solution would be to make the transformation inside an object:
public class ArrayMixer {
private Object[] one;
private Object[] two;
public ArrayMixer(Object[] first, Object[] second) {
//Mix the arrays in the constructor and assign to one and two.
}
public Object[] getOne() { return one; }
public Object[] getTwo() { return two; }
}
I suspect that in your real use case that class and array one and array two can get better names.
Since the specification of your method is that it takes two input arrays and produces output arrays, I agree with you that the method should return both arrays at the same time.
I think that the most natural choice of return value is an int[][] of length 2 (substitute int with whatever type you are using). I don't see any reason it should make the code harder to understand, especially if you specify what the contents of the return value will be.
Edit: in response to your comment, I understand that you have considered this and I am saying that despite your stylistic objections, I don't believe there is a strictly "better" alternative ("better" here being loosely defined in the question).
An alternative approach, largely equivalent to this one, would be to define an object that wraps the two arrays. This has the small distinction of being able to refer to them by names rather than array indices.
The best way to do it would be to do
public void doStuff(int[] array1, int[] array2) {
// Put code here
}
Since Java arrays in Java pass the reference, any modifications made to the arrays will be made to the array itself. This has several caveats
If you are setting it to null you must use a different way (such as encapsulating it in an object)
If you are initializing the array (in the method), you must use a different way
You would use this in the format:
// other method
int[] array1 = new int[20]; // the arrays can be whatever size
int[] array2 = new int[20];
doStuff(array1,array2);
// do whatever you need to with the arrays
Edit: This makes the assumption that it is okay to make changes to the input arrays.
If it isn't, then an object (such as in leonbloy's answer is definitely what is called for).
You strictly cannot return more then one value (think object or primitive) in Java. Maybe you could return an instance of a specific "Result" object which has the two arrays as properties?
You could pass the output arrays as parameters to the method. This may give you more control over memory allocation for the arrays too.
The cleanest and easiest to understand way would be to create a container bean that contains two arrays, and return the container from the method. I'd probably also pass in the container into the method, to keep it symmetric.
The most memory efficient way, assuming both arrays are the same length, would be to pass a multidimensional array - Object[2][n] - where n is the length of the arrays.
If you're really against the arbitrary ordering that comes from a 2d array or a collection, perhaps consider making an inner class that reflects the logic of what you're doing. You could simply define a class that holds two arrays and you could have your method return that, with names and function that reflect the logic of exactly what you're doing.
A simple solution to the above problem is to return as Map.The trick of this question is how you will define the keys to identify the objects, let say there are two
input arrays [a,a,a,a] [b,b,b,b] and two outputs arrays [a,a,b,b] [b,b,a,a]
For that you can use String variable as a key just to identify objects because String variable is immutable, so they can be used as keys.
And as example
Map<String,String[]> method(String[] x,String[] y){
do your stuff..........
Hashmap<String,String[]> map =new HashMap<String,String[]>();
map.put("Object2",[b,b,a,a]);
return map;
}

Java: Iterating HashMap - Algorithm needed

I have a list of names, say 8 names: Joe, Bob, Andrew, Bill, Charlie, Sarah, Ann, Victor
The count of names might differ**.
1) What should I use as name list? Hashmap, Vector, Hashtable, List, ArrayList?
2) I need to match them up like this: Joe-Bob, Andrew-Bill, Charlie-Sarah, Ann-Victor. Could you please show me an example how to make a loop which would do so?
Thank you!
Hashmaps have no order. If you want to insert a list of names like you want, you'd do something like the following (with an array):
for(int i = 0; i < myArray.length - 1; i += 2) {
hashMap.add(myArray[i], myArray[i+1]);
}
1) What should I use as name list? Hashmap, Vector, Hashtable, List, ArrayList?
Well, it depends on your needs :) But, because of the question and because you are mixing collection interfaces (e.g. List) and concrete implementations (e.g. ArrayList or Vector), I think that you should start with the basics. An awesome resource for this is the Trail: Collections from The Java(tm) Tutorials, a really highly recommended reading.
First, you need to understand the various collection interfaces and their purpose. Then you'll choose a concrete implementations. The Interfaces section of the tutorial that I'm quoting below will help you for the first step:
The following list describes the core
collection interfaces:
Collection — the root of the collection hierarchy. A collection
represents a group of objects known as
its elements. The Collection interface
is the least common denominator that
all collections implement and is used
to pass collections around and to
manipulate them when maximum
generality is desired. Some types of
collections allow duplicate elements,
and others do not. Some are ordered
and others are unordered. The Java
platform doesn't provide any direct
implementations of this interface but
provides implementations of more
specific subinterfaces, such as Set
and List. Also see The Collection
Interface section.
Set — a collection that cannot contain duplicate elements. This
interface models the mathematical set
abstraction and is used to represent
sets, such as the cards comprising a
poker hand, the courses making up a
student's schedule, or the processes
running on a machine. See also The Set
Interface section.
List — an ordered collection (sometimes called a sequence). Lists
can contain duplicate elements. The
user of a List generally has precise
control over where in the list each
element is inserted and can access
elements by their integer index
(position). If you've used Vector,
you're familiar with the general
flavor of List. Also see The List
Interface section.
Queue — a collection used to hold multiple elements prior to processing.
Besides basic Collection operations, a
Queue provides additional insertion,
extraction, and inspection operations.
Queues typically, but do not
necessarily, order elements in a FIFO
(first-in, first-out) manner. Among
the exceptions are priority queues,
which order elements according to a
supplied comparator or the elements'
natural ordering. Whatever the
ordering used, the head of the queue
is the element that would be removed
by a call to remove or poll. In a FIFO
queue, all new elements are inserted
at the tail of the queue. Other kinds
of queues may use different placement
rules. Every Queue implementation must
specify its ordering properties. Also
see The Queue Interface section.
Map — an object that maps keys to values. A Map cannot contain duplicate
keys; each key can map to at most one
value. If you've used Hashtable,
you're already familiar with the
basics of Map. Also see The Map
Interface section.
In your case, I don't think that you want a Queue, I'm not sure you need a Map, I think you want to allow duplicate elements so you don't want a Set and this leaves us with a List.
Regarding the concrete implementation, if a thread safe implementation is not needed, ArrayList - or LinkedList, depending on the algorithm in 2) - might be a good choice). But really, have a look at the Implementations section of the tutorial to learn more.
2) I need to match them up like this: Joe-Bob, Andrew-Bill, Charlie-Sarah, Ann-Victor. Could you please show me an example how to make a loop which would do so?
If the initial list can contain duplicate elements, I wouldn't use a Map to store matched names (because a Map cannot contain duplicate keys). So, I'd create a Couple class to store associated names:
public class Couple {
private name1;
private name2;
...
}
and use a List<Couple> to store matched names. But, because the logic of the algorithm is still not clear (does the initial list always contain an odd number of elements? is one element always associated with the immediate next one?), I can't provide more guidance.
It's not exactly clear what you mean by "associating" the names and what you need to do with them. Also you don't say whether the names are unique.
You can pair names this way:
String input = "Joe, Bob, Andrew, Bill, Charlie, Sarah, Ann, Victor";
String names[] = input.split(",");
Map<String, String> output = new HashMap<String, String>();
for (int i=0; i<names.length; i+=2) {
output.put(names[i].trim(), names[i+1].trim());
}
and then do:
output.remove("Joe"); // Joe is paired with Bob
If you also need to associate Bob with Joe, you could do it this way:
String input = "Joe, Bob, Andrew, Bill, Charlie, Sarah, Ann, Victor";
String names[] = input.split(",");
Map<String, String> output = new HashMap<String, String>();
for (int i=0; i<names.length; i+=2) {
String first = names[i].trim();
String second = names[i+1].trim();
output.put(first, second);
output.put(second, first);
}
and then do:
String other = output.remove("Joe");
output.remove(other);
Your choice should depend on the purpose for which you want these names. Do you want efficient search over the list for a given last name? If yes, then you should follow Anon's proposal.
Otherwise, you could just create a class where you could keep information about each person (first name, last name, telephone, etc.) and use a Vector to keep the instances of this class. An example of this class could be:
class PersonDetails {
String firstName;
String lastName;
public PersonDetails(String fn, String ln) {
firstName = fn;
lastName = ln;
}
}
For the insertion of the names in the vector you could use something like the following:
for(int i = 0; i < nameArray.length; i += 2) {
vector.add(new PersonDetails(nameArray[i], nameArray[i+1]));
}
If you have an array to start with but want to remove elements as you process them, first convert it to a List of some kind. Also, removing items from the beginning of an ArrayList can be very expensive, so if you have a lot of names, you may want to use either a LinkedList (though there are very few reasons to actually use this between performance and memory utilization, it is better to have a circular List but this does not come standard with Java).
So, in your case, you know you will be processing the list sequentially so the most efficient I can think of is to create an ArrayList and reverse it then remove from the end, like this:
private Map matchNames(String[] names) {
List namesList = new ArrayList(Arrays.asList(names));
Collections.reverse(namesList);
Map result = new HashMap(namesList.size() / 2);
while (!namesList.isEmpty()) {
result.put(namesList.remove(namesList.size() - 1),
namesList.remove(namesList.size() - 1));
}
return result;
}

Categories

Resources