Converting a HashMap<String, Thing> into a sorted array

Q

qu0ll

I would like to code a method to convert a particular HashMap into a sorted
array. This is what I came up with:

public convert(final HashMap<String, Thing> things)
{
Thing[] tArray = new Thing[things.size()];
Collection<Thing> tCollection = things.values();
int i = 0;
for (Thing t : tCollection)
{
tArray[i++] = t;
}
Arrays.sort(tArray);
return tArray;
}

Well it works but is there a more efficient/elegant way of doing this?
Also, it would be nice to write it in such a way that it would convert any
HashMap not just those using Thing. Can anyone assist?

--
And loving it,

qu0ll
______________________________________________
(e-mail address removed)
(Replace the "SixFour" with numbers to email)
 
J

java

qu0ll,

There are lots of ways to do this depending on your actual goal.

As a HashMap has keys and values, is your end goal to have an array of
{something} in the order that the keys are sorted or based on how the
{something}'s should be ordered on their own?

If its the later, you probably want to create a Comparator for each
{something} you want to sort.

Here is a simple example - not sure if its exactly what you want but
hopefully it helps.

/* Begin qu0ll.java */
import java.util.*;

public class qu0ll {
public static void main(String args[]) {
qu0llSomethingComparator c = new qu0llSomethingComparator();
qu0llSomething[] myArray = new qu0llSomething[args.length];

for (int i = 0; i < args.length; i ++) {
myArray = new qu0llSomething(args);
}

Arrays.sort(myArray, c);

for (qu0llSomething q : myArray) {
System.out.println(q);
}
}
}
/* Begin qu0llSomethingComparator.java */
import java.util.*;

public class qu0llSomethingComparator implements
Comparator<qu0llSomething> {
public int compare(qu0llSomething q1, qu0llSomething q2) {
// Specialized rules for ordering go here

if (q1.getLength() < q2.getLength()) {
return -1;
}
else if (q1.getLength() == q2.getLength()) {
if (q1.hashCode() < q2.hashCode()) {
return -1;
}
else if (q1.hashCode() > q2.hashCode()) {
return 1;
}
else {
return 0;
}
}
else {
return 1;
}
}

public boolean equals(Object o) {
return (o == this);
}
}
/* Begin qu0llSomething.java */
public class qu0llSomething {
private String value;

public qu0llSomething(String value) {
this.value = value;
}

// Will throw NullPointerException if value is null
public int getLength() {
return value.length();
}

public String getValue() {
return value;
}

public String toString() {
return getValue();
}
}

--

Let me know if I can assist further.


-kavaj
 
D

Daniel Dyer

I would like to code a method to convert a particular HashMap into a
sorted
array. This is what I came up with:

public convert(final HashMap<String, Thing> things)
{
Thing[] tArray = new Thing[things.size()];
Collection<Thing> tCollection = things.values();
int i = 0;
for (Thing t : tCollection)
{
tArray[i++] = t;
}
Arrays.sort(tArray);
return tArray;
}

Well it works but is there a more efficient/elegant way of doing this?
Also, it would be nice to write it in such a way that it would convert
any
HashMap not just those using Thing. Can anyone assist?

There's a more concise way:

public Thing[] convert(HashMap<String, Thing> things)
{
Thing[] tArray = things.values().toArray(new Thing[things.size()]);
Arrays.sort(tArray);
return tArray;
}

You could use generics to write a version that will work with any Map (not
just HashMap). The signature would look like this:

public <T extends Comparable> T[] convert(Map<?, T> things)

However, generics and arrays don't mix very well so the implementation
might be a little bit ugly. It's just about impossible to derive the
correct type of T at runtime in this instance, so this might have to
weakened to this:

public Object[] convert(Map<?, ? extends Comparable> things)

Consider using Lists instead of arrays.

Dan.
 
J

java

qu0ll,

There are lots of ways to do this depending on your actual goal.

As a HashMap has keys and values, is your end goal to have an array of
{something} in the order that the keys are sorted or based on how the
{something}'s should be ordered on their own?

If its the later, you probably want to create a Comparator for each
{something} you want to sort.

Here is a simple example - not sure if its exactly what you want but
hopefully it helps.

/* Begin qu0ll.java */
import java.util.*;

public class qu0ll {
public static void main(String args[]) {
qu0llSomethingComparator c = new qu0llSomethingComparator();
qu0llSomething[] myArray = new qu0llSomething[args.length];

for (int i = 0; i < args.length; i ++) {
myArray = new qu0llSomething(args);
}

Arrays.sort(myArray, c);

for (qu0llSomething q : myArray) {
System.out.println(q);
}
}
}
/* Begin qu0llSomethingComparator.java */
import java.util.*;

public class qu0llSomethingComparator implements
Comparator<qu0llSomething> {
public int compare(qu0llSomething q1, qu0llSomething q2) {
// Specialized rules for ordering go here

if (q1.getLength() < q2.getLength()) {
return -1;
}
else if (q1.getLength() == q2.getLength()) {
if (q1.hashCode() < q2.hashCode()) {
return -1;
}
else if (q1.hashCode() > q2.hashCode()) {
return 1;
}
else {
return 0;
}
}
else {
return 1;
}
}

public boolean equals(Object o) {
return (o == this);
}
}
/* Begin qu0llSomething.java */
public class qu0llSomething {
private String value;

public qu0llSomething(String value) {
this.value = value;
}

// Will throw NullPointerException if value is null
public int getLength() {
return value.length();
}

public String getValue() {
return value;
}

public String toString() {
return getValue();
}
}

--

Let me know if I can assist further.


-kavaj
 
L

Lew

Daniel said:
There's a more concise way:

public Thing[] convert(HashMap<String, Thing> things)
{
Thing[] tArray = things.values().toArray(new Thing[things.size()]);
Arrays.sort(tArray);
return tArray;
}

Another way to express the toArray() call is
Thing [] tArray = things.values().toArray( new Thing [0] );

If this is called often, you can create a static final:
private static final Thing [] ARRAY_TEMPLATE = new Thing [0];

that is used in the call:
Thing [] tArray = things.values().toArray( ARRAY_TEMPLATE );

Whether this provides any benefit is questionable in the particular example,
but it's good to know your alternatives.

- Lew
 
D

Daniel Dyer

Daniel said:
There's a more concise way:
public Thing[] convert(HashMap<String, Thing> things)
{
Thing[] tArray = things.values().toArray(new
Thing[things.size()]);
Arrays.sort(tArray);
return tArray;
}

Another way to express the toArray() call is
Thing [] tArray = things.values().toArray( new Thing [0] );

If this is called often, you can create a static final:
private static final Thing [] ARRAY_TEMPLATE = new Thing [0];

that is used in the call:
Thing [] tArray = things.values().toArray( ARRAY_TEMPLATE );

Whether this provides any benefit is questionable in the particular
example, but it's good to know your alternatives.

The version I posted will copy the contents into the array that is passed
in. With your version, a new array will be created since the argument
array is not big enough (unless the map happens to be empty).

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html#toArray(T[])

"If the collection fits in the specified array, it is returned therein.
Otherwise, a new array is allocated with the runtime type of the specified
array and the size of this collection."

This is not the neatest method in the API.

Dan.
 
L

Lew

Daniel said:
There's a more concise way:
public Thing[] convert(HashMap<String, Thing> things)
{
Thing[] tArray = things.values().toArray(new Thing[things.size()]);
Arrays.sort(tArray);
return tArray;
}
Another way to express the toArray() call is
Thing [] tArray = things.values().toArray( new Thing [0] );

Daniel said:
The version I posted will copy the contents into the array that is
passed in. With your version, a new array will be created since the
argument array is not big enough (unless the map happens to be empty).

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html#toArray(T[])


"If the collection fits in the specified array, it is returned therein.
Otherwise, a new array is allocated with the runtime type of the
specified array and the size of this collection."

Dan.

--Daniel Dyer
http://www.uncommons.org

That's exactly right.

In
Thing[] tArray = things.values().toArray(new Thing[things.size()]);

the "new" of the returned array is explicit and done by the client code.

In
public static final Thing [] ARRAY_TEMPLATE = new Thing [0];
...
Thing [] tArray = things.values().toArray( ARRAY_TEMPLATE );

the "new" of the returned array is hidden in the toArray() call.
> This is not the neatest method in the API.

I guess the reason for the second idiom is convenience for the programmer.

- Lew
 
P

Patricia Shanahan

Lew wrote:
....
In
Thing[] tArray = things.values().toArray(new Thing[things.size()]);

the "new" of the returned array is explicit and done by the client code.

In
public static final Thing [] ARRAY_TEMPLATE = new Thing [0];
...
Thing [] tArray = things.values().toArray( ARRAY_TEMPLATE );

the "new" of the returned array is hidden in the toArray() call.
This is not the neatest method in the API.

I guess the reason for the second idiom is convenience for the programmer.

- Lew

I think the second idiom also has an advantage when depending on a
synchronized list for your synchronization. Even if the list is
shrinking, there is no way to end up with a larger array than is needed.

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top