Skip to Main Content

Java Programming

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

simpler way to sort 2-d string array?

RichFOct 7 2010 — edited Oct 23 2010
I have a long 2d string array, and I would like to sort by the 2nd value. It originates as:
    public static final String names[][] = {
	{"000000", "Black"},
	{"000080", "Navy Blue"},
	{"0000C8", "Dark Blue"},
	{"0000FF", "Blue"},
        {"000741", "Stratos"},
        ...
	{"FFFFF0", "Ivory"},
	{"FFFFFF", "White"}
    };
As you can see, they are pre-sorted by the hex values. That is useful for part of the app.

There are 1,567 entries. I would like to alphabetize the color names and place them in a list widget. I need to keep the associated hex color values with the name values. All I can think of to do something like:

1) make a temporary long 1-d string array
2) fill it by loop that appends the hex values to the name values: temp[i] = new String (names[1] + names[i][0])
3) sort temp[] with built in Java sort
4) make a permanent new string array, hexValues[] for the hex values
5) copy the last 6 characters of each item to hexValues[]
6) truncate the last 6 characters of each item in temp[]
7) build list widget with temp[]

Is there a more elegant way? What I'd really like to do is build a 1-d array of int's, with the values representing the alphabetized locations of the names. However, I don't see any built-in which would do that kind of indirect sort.

- - - - - - - - - -
Second question -- Can the backgrounds of each item in a list widget be a different color? Ideally the list would show the color name in black or white, and the its color value as background. Specifically, I'm trying to build the list accomplished by the Javascript code here:

* http://chir.ag/projects/name-that-color/

and add it to my Java interactive color wheel:

* http://r0k.us/graphics/SIHwheel.html

- - - - - - - - - -
BTW, I have converted his name that color Javascript (ntc.js) to a native Java class. It is freely distributable, and I host it here:

* http://r0k.us/source/ntc.java

-- Rich

Edited by: RichF on Oct 7, 2010 7:04 PM
Silly forum software; I can't see what made it go italic at the word new.
This post has been answered by 804650 on Oct 13 2010
Jump to Answer

Comments

camickr
The [url http://tips4java.wordpress.com/2008/10/16/column-comparator/]Column Comparator should work.
796440
That looks like it should not be a 2D array, but rather a 1D array of a class that encapsulates those two properties.
YoungWinston
jverd wrote:
That looks like it should not be a 2D array, but rather a 1D array of a class that encapsulates those two properties.
Like Color perhaps? Or some wrapper to it.

Winston
RichF
Rob, thanks for the link. I'll think about using the Column Comparator.

JVerd, since ntc.class is a port of ntc.js, I am hesitant to alter things too much. Until the task of making the alphabetized list widget came to the fore, the existing design was fine. Plus I guess I'm dense. I don't see how having an array of .hexColor : .colorName pairs would improves matters. All I see is that it gives specific names to the 2nd dimension of the 2-d array. I.e., instead of:

names[420][0] and names [420][1]

one would have

names[420].hexColor and names[420].colorName

What am I missing?

Winston, extending the Color class for my limited needs seems like overkill. All I need to do is make the alphabetized list of color names, and make sure I still know what hex value goes with what color name in the list widget.

I appreciate the feedback though. Does anyone know if the background color of items in a list widget can be set individually?
camickr
What am I missing?
Object Oriented design concepts.

Its better and easier to work with Objects then you can implement a "natural sort order" or provide custom sort orders. For example:
/*
**  Use the Collections API to sort a List for you.
**
**  When your class has a "natural" sort order you can implement
**  the Comparable interface.
**
**  You can use an alternate sort order when you implement
**  a Comparator for your class.
*/
import java.util.*;

public class Person implements Comparable<Person>
{
	String name;
	int age;

	public Person(String name, int age)
	{
	   	this.name = name;
	   	this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public String toString()
	{
		return name + " : " + age;
	}

	/*
	**  Implement the natural order for this class
	*/
	public int compareTo(Person p)
	{
		return getName().compareTo(p.getName());
	}

	static class AgeComparator implements Comparator<Person>
	{
		public int compare(Person p1, Person p2)
		{
			int age1 = p1.getAge();
			int age2 = p2.getAge();

			if (age1 == age2)
				return 0;
			else if (age1 > age2)
				return 1;
			else
				return -1;
		}
	}

	public static void main(String[] args)
	{
		List<Person> people = new ArrayList<Person>();
		people.add( new Person("Homer", 38) );
		people.add( new Person("Marge", 35) );
		people.add( new Person("Bart", 15) );
		people.add( new Person("Lisa", 13) );

		// Sort by natural order

		Collections.sort(people);
		System.out.println("Sort by Natural order");
		System.out.println("\t" + people);

		// Sort by reverse natural order

		Collections.sort(people, Collections.reverseOrder());
		System.out.println("Sort by reverse natural order");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by age

		Collections.sort(people, new Person.AgeComparator());
//		Collections.sort(people, new PersonAgeComparator());
		System.out.println("Sort using Age Comparator");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by descending age

		Collections.sort(people, Collections.reverseOrder(new Person.AgeComparator()));
//		Collections.sort(people, Collections.reverseOrder(new PersonAgeComparator()));
		System.out.println("Sort using Reverse Age Comparator");
		System.out.println("\t" + people);
	}
}
darrylburke
RichF wrote:
Does anyone know if the background color of items in a list widget can be set individually?
Go through the sections on custom renderers in the Swing tutorial and search the Swing forum for examples. Start a new thread in the Swing forum if you still have a question.
http://download.oracle.com/javase/tutorial/uiswing/components/list.html#renderer
http://www.google.com/search?q=list+cell+renderer+background+site:forums.sun.com

db
796440
RichF wrote:
Rob, thanks for the link. I'll think about using the Column Comparator.

JVerd, since ntc.class is a port of ntc.js, I am hesitant to alter things too much.
That's a common mistake people make. They try to directly translate from one language to another, rather than understanding what the program does in the source language and then creating equivalent functionality using appropriate idioms in the target language. It's akin to trying to do word for word translations in natural language. "Asoko biiru nondeiru hito wa kono hon wo kaita" in Japanese would become "Over there beer is drinking person as for this book [object marker] wrote," when a more sensible translation would be, "The person drinking beer over there wrote this book."
Until the task of making the alphabetized list widget came to the fore, the existing design was fine.
The code worked. That doesn't mean the design is fine.
What am I missing?
As camickr indicated, it's one of the key points of OO--define a named type that encapsulates the data (and behavior) that expresses that type's abstraction.
RichF
Rob, wow. Thanks for the complete example. I understand it, and I may well go that route. I think I'd implement as a second class to complement ntc.java, though. Its main purpose is: given an arbitrary 24-bit color (in hex), find the closest named color. Return both the hexString and name of that color. There is no sorting involved; it is just an algorithmic search. Plus I'd need to populate the new list somehow. The source data might as well come from a 2-d string array. (I can't see doing 1,567 inline .add's -- perhaps I'm still not object oriented enough... )

Curiously your example helped me understand what the heck Mr. Mehta was doing in his ntc_main.js that runs on his "Name that Color" page.
var ntc_main = {

  fb: null,

  init: function() {

    srtnm = ntc.names;
    srtnm.sort(ntc_main.nameSort);
    clrop = new Array();

    for(i = 0; i < srtnm.length; i++)
    {
      clr = srtnm[0];
rgb = ntc.rgb("#" + clr);
alt = ((rgb[0] + rgb[1] + rgb[2])/3 < 128);
clrop.push("<option value='" + clr + "' " + (alt ? "class='w'" : "") + "style='background:#" + clr + "'>" + srtnm[i][1] + "</option>");
}
....
},
nameSort: function(a, b) {
return (a[1] > b[1] ? 1 : (a[1] < b[1] ? -1 : 0));
},
...
}
Not knowing Javascript, I couldn't figure out how nameSort was sorting anything. It was just returning -1, 0, or 1. Your example let me see that he was defining a comparator, which was actually used in "srtnm.sort(ntc_main.nameSort);". I also see that he is not using a "Javascript list widget", but simply building an HTML form, which does allow different background colors for each element.

Darryl, unfortunately the Interactive Color Wheel is an old app, being first written back in 1998 under JDK 1.1. I used AWT -- did Swing even exist back then? If it did, the Java books I bought weren't recent enough to mention it. I should have mentioned AWT in the first place. With two GUI toolkits to choose from, I should have been clear.

JVerd, as I mentioned at the top of this post, the scope of ntc.java is limited. If I write the second class, ntc.names[][] will be a fine source of data from which to build the sortable list.
RichF
User pietblok provided a really nice short example of a color list widget in response to my thread in the Abstract Window Toolkit (AWT) forum:

* 1557347

He reinforced Darryl's advice concerning implementing in Swing, which I will do.

Not only that, his example shows how to elegantly sort a 2-d array by the second column. It involves a custom comparator, which basically does what the nameSort() Javascript comparator does in my previous post.

That said, I plan to implement an ntcSorter class along the lines of camickr's example. Last night it occurred to me that I need not only display the list in alphabetical order. The web tracker for my page shows that a good number of people find it with Google searches such as: color wheel names for blue

What better way to answer that kind of specific query than to offer a sort by hue? Specifically I'll add a third primitive to ntcSorter. There will be hex, name, and hsi. HSI will be a pre-calculated int of form "hhhhhhssssiiiiii", ie, 6 high-order bits for hue, 4 middle bits for saturation, and 6 lower bits for intensity. Sorting by hsi will group all the yellows together, the cyans, etc. Because hue is a clock primitive (0 degrees is the same as 360 degrees), red at 0 degrees is split numerically from the close reds at the other end. I'll likely overpopulate the hue-sorted list at the top and bottom repeating a few values from the other side of the hueborhood.

By default the list will be alphabetical. The user will be able to toggle to a list sorted by hue, and overpopulated at each end of red. Does this sound like a good idea to you guys?

-- Rich

Edited by: RichF on Oct 9, 2010 12:16 PM
RichF
I am implementing a sort infrastructure along the lines of camickr's working example, above. Part of my problem is that I am new to both lists and collections. I've tried searching, and I cannot figure out why the compiler doesn't like my "new":
public class colorName implements Comparable<colorName>
{
    String	name, hex;
    int		hsi;
    static List<colorName> colorNames;

    public colorName(String name, String hex)
    {
	float	hsb[] = {0f, 0f, 0f};
	int	rgb[] = {0, 0, 0};
	int	h, s, b;	// b for brightness, same as i

	this.name = name;
	this.hex  = hex;

	// Now we need to calculate hsi,
        ...
	this.hsi = (h << 10) + (s << 6) + b;  //  hhhhhhssssiiiiii
    }

    ...

    /**
    ***   findColorName() performs 3 functions.  First, it
    *** will auto-initialize itself if necessary.  Second,
    *** it will perform 3 sorts:
    ***   -3) byHSI:  sort by HSI and return first element of sorted list
    ***   -2) byNAME: sort by name and return first element of list
    ***   -1) byHEX:  (re)reads ntc.names, which is already sorted by HEX;
    ***               returns first element of list
    *** Third, on 0 or greater, will return the nth element of list
    *** Note: ntc.init() need not have been called.
    **/
    public colorName findColorName(int which)
    {
	if (which < -3)  which = -3;
	if (which >= ntc.names.length)  which = ntc.names.length - 1;
	if (which == -1)  colorNames = null;	// free up for garbage collection

	if (colorNames == null)
	{   // (re)create list
	    colorNames = new ArrayList<colorName>(ntc.names.length);
	    for (int i = 0; i < ntc.names.length; i++)
	        colorNames.add(new colorName(ntc.names[1], ntc.names[0]));
	}

        if (which == -1)  return(colorNames.get(0));
        ...
    }
}
On compilation, I receive:
D:\progming\java\ntc>javac colorName.java
colorName.java:117: cannot find symbol
symbol  : constructor colorName(java.lang.String[],java.lang.String[])
location: class colorName
                colorNames.add(new colorName(ntc.names[1], ntc.names[0]));
                               ^
1 error
Line 117 is the second-to-last executable line in code block. I know it is finding the ntc.names[][] array the ntc.class file. I had forgotten to compile ntc.java, and there were other errors, such as in line 115 where it couldn't find ntc.names.length. Compare camickr's two lines:
		List<Person> people = new ArrayList<Person>();
		people.add( new Person("Homer", 38) );
As far as I can tell, I'm doing exactly the same thing. If you have any other feedback, feel free to make it. The full source may be found at:

* http://r0k.us/rock/Junk/colorName.java

PS1: I know I don't need the parenthesis in my return's. It's an old habit, and they look funny to me without them.
PS2: My original design had the "static List<colorName> colorNames;" line defined within the findColorName() method. The compiler did not like that; it appears to be that one cannot have static variables within methods. Anyway, that's why I don't have separate sorting and getting methods. I'm learning; "static" does not mean, "keep this baby around". Its meaning is, "there is only one of these babies per class".

-- Rich
804650
Answer
People forget that a 2D array is basically a 1D array of arrays.
colorNames.add(new colorName(ntc.names[1], ntc.names[0]));
The above code is attempting to pass arrays as parameters to your constructor but your constructor is expecting a single String object.
Marked as Answer by RichF · Sep 27 2020
RichF
Gack! Thanks for the quick response, Pinto. :) I don't know how long I studied that line and missed the obvious. I knew it was a 2-d array. In fact, it was in a loop so I could grab each pair of values. Sigh ...

Edited by: RichF on Oct 12, 2010 10:14 PM
RichF
The sorter class seems to be working. I added a main() for stand-alone testing. If interested, you can download:

* http://r0k.us/rock/Junk/colorName.java
* http://r0k.us/rock/Junk/ntc.java

You'll need both. As stated above, I decided to keep the files separate because colorName.class goes beyond what ntc.class needs to do. To run the test, compile them, then type "java colorName -3". Valid parameters are -3, -2, and -1; no parameter yields a help line. It appears to work great. (FTR, ntc.class has a main(), also for testing.) Thanks, Rob, for the clear example.

Oh, I ended up declaring:

static private List<colorName> colorNames;

It was my intent all along that users of the class not have direct access to the ArrayList.

My next update here, unless someone has further feedback, will be a link to a working Interactive Color Wheel with a resortable, colored, list widget. :)

-- Rich
RichF
My next update here, unless someone has further feedback, will be a link to a working Interactive Color Wheel with a resortable, colored, list widget.
* http://r0k.us/graphics/SIHwheel.html

Comments welcome.
RichF
Sigh. Everything has been hunky dory, except for some Mac users reporting that my JDK 1.6 applet won't run for them. So, based on feedback from one of them, I decided to target compile for 1.4. There have been several issues:

<li> no enum. simple, define a bunch of class-level final ints.
<li> no autoboxing. simple. add .intValue() to the end of problematic Integer calculations
<li> no generics. Ack! camickr's example (which I implemented) is full of generics :(

I have several options:

1) target 1.5 instead of 1.4, which should give me all the goodies, but will probably continue to lock out some Mac users
2) convert Rob's example to use arrays rather than lists. I know now how to sort arrays directly by any column.
3) learn more about generics and how to get rid of them

Suggestions?
Kayaman
RichF wrote:
1) target 1.5 instead of 1.4, which should give me all the goodies, but will probably continue to lock out some Mac users
Yes. If the mac users don't have 1.5 Java, they probably won't have 1.4 either. And 1.4 has been EOLed for so long already...
2) convert Rob's example to use arrays rather than lists. I know now how to sort arrays directly by any column.
No. Also you could just turn them into non-generic lists, it just makes the code uglier.
3) learn more about generics and how to get rid of them
No.
I mean yes, learn more about generics, but that's not a solution to the problems you're having.
camickr
no generics. Ack! camickr's example (which I implemented) is full of generics
If you are referring to my "Person" example, then you just need to do a lot more casting, but the logic doesn't change:
/*
**  Use the Collections API to sort a List for you.
**
**  When your class has a "natural" sort order you can implement
**  the Comparable interface.
**
**  You can use an alternate sort order when you implement
**  a Comparator for your class.
*/
import java.util.*;

public class Person2 implements Comparable
{
	String name;
	int age;

	public Person2(String name, int age)
	{
	   	this.name = name;
	   	this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public String toString()
	{
		return name + " : " + age;
	}

	/*
	**  Implement the natural order for this class
	*/
	public int compareTo(Object o)
	{
		Person2 p = (Person2)o;
		return getName().compareTo(p.getName());
	}

	static class AgeComparator implements Comparator
	{
		public int compare(Object o1, Object o2)
		{
			Person2 p1 = (Person2)o1;
			Person2 p2 = (Person2)o2;

			int age1 = p1.getAge();
			int age2 = p2.getAge();

			if (age1 == age2)
				return 0;
			else if (age1 > age2)
				return 1;
			else
				return -1;
		}
	}

	public static void main(String[] args)
	{
		List people = new ArrayList();
		people.add( new Person2("Homer", 38) );
		people.add( new Person2("Marge", 35) );
		people.add( new Person2("Bart", 15) );
		people.add( new Person2("Lisa", 13) );

		// Sort by natural order

		Collections.sort(people);
		System.out.println("Sort by Natural order");
		System.out.println("\t" + people);

		// Sort by reverse natural order

		Collections.sort(people, Collections.reverseOrder());
		System.out.println("Sort by reverse natural order");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by age

		Collections.sort(people, new Person2.AgeComparator());
//		Collections.sort(people, new Person2AgeComparator());
		System.out.println("Sort using Age Comparator");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by descending age

		Collections.sort(people, Collections.reverseOrder(new Person2.AgeComparator()));
//		Collections.sort(people, Collections.reverseOrder(new Person2AgeComparator()));
		System.out.println("Sort using Reverse Age Comparator");
		System.out.println("\t" + people);
	}
}
RichF
Thanks, kayaman and camickr! I was about to follow Kayaman's advice and target 1.5, but then camickr posted the generic-less example. Since I had already made the other necessary edits for 1.4, I chose to go genericless in the sort class, and compiled to target 1.4. I've put a lot of work into this, and I hate to lock anyone out if I don't need to. As time goes by, I'll likely reverse this decision and target a later release.

Anyway, the latest and backwardest is up:

* http://r0k.us/graphics/SIHwheel.html

I forgot to say that bypassing the 1.5 features yields smaller classes, and eliminated the enum class altogether. Not that it matters much on the high speed web, but it made me feel a little better about my decision.

-- Rich

Edited by: RichF on Oct 23, 2010 3:09 PM
1 - 18
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Nov 20 2010
Added on Oct 7 2010
18 comments
8,252 views