Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #38519 > unrolled thread

Is there a better way to group and sort objects?

Started byEric Douglas <e.d.programmer@gmail.com>
First post2018-08-07 06:00 -0700
Last post2018-08-14 05:47 -0700
Articles 20 on this page of 23 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 06:00 -0700
    Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 09:44 -0400
      Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 11:33 -0400
      Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 10:22 -0700
        Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 14:16 -0400
          Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 14:36 -0400
          Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 12:13 -0700
            Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 16:00 -0400
    Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 08:20 +0000
      Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 06:57 -0400
        Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 11:08 +0000
        Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 11:22 +0000
          Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 07:45 -0400
            Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 14:12 +0000
          Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 05:50 -0700
            Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 09:23 -0400
              Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 06:47 -0700
                Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 10:31 -0400
                  Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 08:24 -0700
            Re: Is there a better way to group and sort objects? Robert Klemme <shortcutter@googlemail.com> - 2018-08-14 14:06 +0200
              Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-14 05:49 -0700
    Re: Is there a better way to group and sort objects? Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2018-08-09 16:06 +0200
      Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-14 05:47 -0700

Page 1 of 2  [1] 2  Next page →


#38519 — Is there a better way to group and sort objects?

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-07 06:00 -0700
SubjectIs there a better way to group and sort objects?
Message-ID<8c045ff4-98c5-4253-9136-b26b34cf8f77@googlegroups.com>
I want to combine and sort objects by key properties and merge their secondary properties.  Is there a better way?  This is what I came up with..

public abstract class TestStatic {
	private static class TestClass extends Object implements Comparable<Object> {
		private int var1;
		private int var2;

		@Override
		public int compareTo(Object compareMe) {
			if (compareMe == null || compareMe.getClass() != getClass()) {
				return 1;
			}
			return var1 - ((TestClass) compareMe).getVar1();
		}

		@Override
		public boolean equals(Object compareMe) {
			if (compareMe == null || compareMe.getClass() != getClass()) {
				return false;
			}
			if (var1 != ((TestClass) compareMe).getVar1()) {
				return false;
			}
			return true;
		}
		
		public String toString() {
			return String.valueOf(var1);
		}

		public void setVar1(int value) {
			var1 = value;
		}

		public int getVar1() {
			return var1;
		}

		public void setVar2(int value) {
			var2 = value;
		}

		public int getVar2() {
			return var2;
		}
	}
	public static void main(final String[] args) {
		HashMap<String,TestClass> hm = new HashMap<>();
		TestClass test1 = new TestClass();
		test1.setVar1(3);
		test1.setVar2(12);
		hm.put(test1.toString(),test1);
		TestClass test2 = new TestClass();
		test2.setVar1(4);
		if (hm.containsKey(test2.toString())) {
			test2 = hm.get(test2.toString());
			test2.setVar2(test2.getVar2() + 42);
		} else {
			test2.setVar2(42);
			hm.put(test2.toString(), test2);
		}
		TestClass test3 = new TestClass();
		test3.setVar1(3);
		if (hm.containsKey(test3.toString())) {
			test3 = hm.get(test3.toString());
			test3.setVar2(test3.getVar2() + 55);
		} else {
			test3.setVar2(55);
			hm.put(test3.toString(), test3);
		}
		ArrayList<TestClass> al = new ArrayList<>();
		al.addAll(hm.values());
		Collections.sort(al);
		for (TestClass t1 : al) {
			System.out.println(t1.getVar1() + " " + t1.getVar2());
		}
	}
}

[toc] | [next] | [standalone]


#38520

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-07 09:44 -0400
Message-ID<pkc7nj$6du$1@dont-email.me>
In reply to#38519
On 8/7/2018 9:00 AM, Eric Douglas wrote:
> I want to combine and sort objects by key properties and merge their secondary properties.  Is there a better way?  This is what I came up with..
> 
> public abstract class TestStatic {
> 	private static class TestClass extends Object implements Comparable<Object> {
> 		private int var1;
> 		private int var2;
> 
> 		@Override
> 		public int compareTo(Object compareMe) {
> 			if (compareMe == null || compareMe.getClass() != getClass()) {
> 				return 1;
> 			}
> 			return var1 - ((TestClass) compareMe).getVar1();
> 		}

     Note that this method violates the Comparable contract.  If you use
this compareTo() method with Arrays.sort() or Collections.sort() or a
SortedMap or whatever, and the objects being compared are a mixture of
different TestClass subclasses, there's no telling what might happen.

> 		@Override
> 		public boolean equals(Object compareMe) {
> 			if (compareMe == null || compareMe.getClass() != getClass()) {
> 				return false;
> 			}
> 			if (var1 != ((TestClass) compareMe).getVar1()) {
> 				return false;
> 			}
> 			return true;
> 		}
> 		
> 		public String toString() {
> 			return String.valueOf(var1);
> 		}
> 
> 		public void setVar1(int value) {
> 			var1 = value;
> 		}
> 
> 		public int getVar1() {
> 			return var1;
> 		}
> 
> 		public void setVar2(int value) {
> 			var2 = value;
> 		}
> 
> 		public int getVar2() {
> 			return var2;
> 		}
> 	}
> 	public static void main(final String[] args) {
> 		HashMap<String,TestClass> hm = new HashMap<>();
> 		TestClass test1 = new TestClass();
> 		test1.setVar1(3);
> 		test1.setVar2(12);
> 		hm.put(test1.toString(),test1);
> 		TestClass test2 = new TestClass();
> 		test2.setVar1(4);
> 		if (hm.containsKey(test2.toString())) {
> 			test2 = hm.get(test2.toString());
> 			test2.setVar2(test2.getVar2() + 42);
> 		} else {
> 			test2.setVar2(42);
> 			hm.put(test2.toString(), test2);
> 		}

     Alternatively, you might take advantage of the fact that Map::put
returns the old key (if any) associated with its value:

	TestClass test2 = new TestClass();
	test2.setVar1(4);
	TestClass oldTest = hm.put(test2.toString(), test2);
	test2.setVar2(42 + (oldTest == null ? 0 : oldTest.getVar2()));

... thus cutting the number of map searches in half.
	
> 		TestClass test3 = new TestClass();
> 		test3.setVar1(3);
> 		if (hm.containsKey(test3.toString())) {
> 			test3 = hm.get(test3.toString());
> 			test3.setVar2(test3.getVar2() + 55);
> 		} else {
> 			test3.setVar2(55);
> 			hm.put(test3.toString(), test3);
> 		}

     Similarly here.

> 		ArrayList<TestClass> al = new ArrayList<>();
> 		al.addAll(hm.values());
> 		Collections.sort(al); > 		for (TestClass t1 : al) {
> 			System.out.println(t1.getVar1() + " " + t1.getVar2());
> 		}
> 	}
> }


-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-seven days to go.

[toc] | [prev] | [next] | [standalone]


#38521

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-07 11:33 -0400
Message-ID<pkce4e$h0i$1@dont-email.me>
In reply to#38520
On 8/7/2018 9:44 AM, Eric Sosman wrote:
> On 8/7/2018 9:00 AM, Eric Douglas wrote:
>> I want to combine and sort objects by key properties and merge their 
>> secondary properties.  Is there a better way?  This is what I came up 
>> with..
>>
>> public abstract class TestStatic {
>>     private static class TestClass extends Object implements 
>> Comparable<Object> {
>>         private int var1;
>>         private int var2;
>>
>>         @Override
>>         public int compareTo(Object compareMe) {
>>             if (compareMe == null || compareMe.getClass() != 
>> getClass()) {
>>                 return 1;
>>             }
>>             return var1 - ((TestClass) compareMe).getVar1();
>>         }
> 
>      Note that this method violates the Comparable contract.  If you use
> this compareTo() method with Arrays.sort() or Collections.sort() or a
> SortedMap or whatever, and the objects being compared are a mixture of
> different TestClass subclasses, there's no telling what might happen.

     Now that I think of it, the method violates Comparable in at least
two other ways, too.

     Violation #1:

	TestClass test = new TestClass();
	Integer that = 42;
	int one = test.compareTo(that);
	int two = that.compareTo(test);

Comparable requires that `one' and `two' have opposite signs or are
both zero, but the final line won't even compile, much less yield an
acceptable result.  (Because of the antisymmetry requirement, I think
it is impossible for *any* class to implement Comparable<Object>.)

     Violation #2:

	TestClass small = new TestClass();
	TestClass medium = new TestClass();
	TestClass large = new TestClass();
	small.setVar1(Integer.MIN_VALUE);
	large.setVar1(Integer.MAX_VALUE);
	int smallMedium = small.compareTo(medium);  // small < medium
	int mediumLarge = medium.compareTo(large);  // medium < large
	int smallLarge = small.compareTo(large);    // small > large !!!

Comparable must define a /total order/, which must be transitive: If
X is less than Y and Y is less than Z, X must be less than Z.

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-seven days to go.

[toc] | [prev] | [next] | [standalone]


#38522

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-07 10:22 -0700
Message-ID<fbdc6564-aa69-4db8-9e90-393ea9469f05@googlegroups.com>
In reply to#38520
On Tuesday, August 7, 2018 at 9:44:30 AM UTC-4, Eric Sosman wrote:
> On 8/7/2018 9:00 AM, Eric Douglas wrote:
> > I want to combine and sort objects by key properties and merge their secondary properties.  Is there a better way?  This is what I came up with..
> > 
> > public abstract class TestStatic {
> > 	private static class TestClass extends Object implements Comparable<Object> {
> > 		private int var1;
> > 		private int var2;
> > 
> > 		@Override
> > 		public int compareTo(Object compareMe) {
> > 			if (compareMe == null || compareMe.getClass() != getClass()) {
> > 				return 1;
> > 			}
> > 			return var1 - ((TestClass) compareMe).getVar1();
> > 		}
> 
>      Note that this method violates the Comparable contract.  If you use
> this compareTo() method with Arrays.sort() or Collections.sort() or a
> SortedMap or whatever, and the objects being compared are a mixture of
> different TestClass subclasses, there's no telling what might happen.
> 

While in my real code which follows this structure it makes no sense to ever compare this to a null or instance of different class, I just want it to do whatever stupid comparison makes sense in that case.  Would splitting the class condition make more sense?
			if (compareMe == null) {
				return 1;
			}
			if (compareMe.getClass() != getClass()) {
				return Integer.compare(hashCode(),compareMe.hashCode());
			}


> > 		@Override
> > 		public boolean equals(Object compareMe) {
> > 			if (compareMe == null || compareMe.getClass() != getClass()) {
> > 				return false;
> > 			}
> > 			if (var1 != ((TestClass) compareMe).getVar1()) {
> > 				return false;
> > 			}
> > 			return true;
> > 		}
> > 		
> > 		public String toString() {
> > 			return String.valueOf(var1);
> > 		}
> > 
> > 		public void setVar1(int value) {
> > 			var1 = value;
> > 		}
> > 
> > 		public int getVar1() {
> > 			return var1;
> > 		}
> > 
> > 		public void setVar2(int value) {
> > 			var2 = value;
> > 		}
> > 
> > 		public int getVar2() {
> > 			return var2;
> > 		}
> > 	}
> > 	public static void main(final String[] args) {
> > 		HashMap<String,TestClass> hm = new HashMap<>();
> > 		TestClass test1 = new TestClass();
> > 		test1.setVar1(3);
> > 		test1.setVar2(12);
> > 		hm.put(test1.toString(),test1);
> > 		TestClass test2 = new TestClass();
> > 		test2.setVar1(4);
> > 		if (hm.containsKey(test2.toString())) {
> > 			test2 = hm.get(test2.toString());
> > 			test2.setVar2(test2.getVar2() + 42);
> > 		} else {
> > 			test2.setVar2(42);
> > 			hm.put(test2.toString(), test2);
> > 		}
> 
>      Alternatively, you might take advantage of the fact that Map::put
> returns the old key (if any) associated with its value:
> 
> 	TestClass test2 = new TestClass();
> 	test2.setVar1(4);
> 	TestClass oldTest = hm.put(test2.toString(), test2);
> 	test2.setVar2(42 + (oldTest == null ? 0 : oldTest.getVar2()));
> 
> ... thus cutting the number of map searches in half.
> 	

Interesting.  So I said if the map contains object 1 let's leave it there and set the values which may be different from object 2.  This requires access to the map once to check for object 1 and once to insert object 2 if matching object 1 is not found.  You're saying do a flip flop, stick object 2 in the map regardless, which gets object 1 out if it's there.  Then if the return value from the .put is not null copy it's distinct values into object 2.

In one real world implementation the objects represent contacts (people).  The keys are name, phone number, and email address.  These people merge in from different sources.  Each source is a distinct field.  One source calls setShipToContact(true), one calls .setMailToContact(true), another calls .setBillToContact(true).  While each may only have to call one distinct method, it may be more efficient for all to call all methods to copy from object 1 to object 2 when a duplicate is found, than to ask the map .contains then tell the map to .put.

> > 		TestClass test3 = new TestClass();
> > 		test3.setVar1(3);
> > 		if (hm.containsKey(test3.toString())) {
> > 			test3 = hm.get(test3.toString());
> > 			test3.setVar2(test3.getVar2() + 55);
> > 		} else {
> > 			test3.setVar2(55);
> > 			hm.put(test3.toString(), test3);
> > 		}
> 
>      Similarly here.
> 

What am I missing here?

> > 		ArrayList<TestClass> al = new ArrayList<>();
> > 		al.addAll(hm.values());
> > 		Collections.sort(al); > 		for (TestClass t1 : al) {
> > 			System.out.println(t1.getVar1() + " " + t1.getVar2());
> > 		}
> > 	}
> > }

[toc] | [prev] | [next] | [standalone]


#38523

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-07 14:16 -0400
Message-ID<pkcnmi$ioq$1@dont-email.me>
In reply to#38522
On 8/7/2018 1:22 PM, Eric Douglas wrote:
> On Tuesday, August 7, 2018 at 9:44:30 AM UTC-4, Eric Sosman wrote:
>> On 8/7/2018 9:00 AM, Eric Douglas wrote:
>>> I want to combine and sort objects by key properties and merge their secondary properties.  Is there a better way?  This is what I came up with..
>>>
>>> public abstract class TestStatic {
>>> 	private static class TestClass extends Object implements Comparable<Object> {
>>> 		private int var1;
>>> 		private int var2;
>>>
>>> 		@Override
>>> 		public int compareTo(Object compareMe) {
>>> 			if (compareMe == null || compareMe.getClass() != getClass()) {
>>> 				return 1;
>>> 			}
>>> 			return var1 - ((TestClass) compareMe).getVar1();
>>> 		}
>>
>>       Note that this method violates the Comparable contract.  If you use
>> this compareTo() method with Arrays.sort() or Collections.sort() or a
>> SortedMap or whatever, and the objects being compared are a mixture of
>> different TestClass subclasses, there's no telling what might happen.
>>
> 
> While in my real code which follows this structure it makes no sense to ever compare this to a null or instance of different class, I just want it to do whatever stupid comparison makes sense in that case.  Would splitting the class condition make more sense?
> 			if (compareMe == null) {
> 				return 1;
> 			}
> 			if (compareMe.getClass() != getClass()) {
> 				return Integer.compare(hashCode(),compareMe.hashCode());
> 			}

     It still fails to be antisymmetric:

	TestClass obj = new TestClass();
	TestClass nil = null;
	int one = obj.compareTo(nil);  // yields +ve
	int two = nil.compareTo(obj);  // should yield -ve, but throws

(This discussion seems oddly familiar: Have we had it before?  Ah, yes:
Google Groups finds a thread from two years ago titled "Why not String
compare?" and another from one year back titled "What's the best way to
make a cross string set?"  Both threads discuss implementing Comparable
and/or Comparator, and the latter touches upon the impossibility of
implementing Comparable<Object>.  Will this query be an annual event? :)

>>       Alternatively, you might take advantage of the fact that Map::put
>> returns the old key (if any) associated with its value:

     Aside: Um, er, Map::put returns the old *value* (if any) associated
with its *key*, yeah, that's what I meant, yeah, obviously, of course.
"I misspoke," as the President so eloquently and so often says.

>>
>> 	TestClass test2 = new TestClass();
>> 	test2.setVar1(4);
>> 	TestClass oldTest = hm.put(test2.toString(), test2);
>> 	test2.setVar2(42 + (oldTest == null ? 0 : oldTest.getVar2()));
>>
>> ... thus cutting the number of map searches in half.


> In one real world implementation the objects represent contacts (people).  The keys are name, phone number, and email address.  These people merge in from different sources.  Each source is a distinct field.  One source calls setShipToContact(true), one calls .setMailToContact(true), another calls .setBillToContact(true).  While each may only have to call one distinct method, it may be more efficient for all to call all methods to copy from object 1 to object 2 when a duplicate is found, than to ask the map .contains then tell the map to .put.

     Using the value returned by put() saves one map lookup in the case
when the key is already present.  (When I wrote "in half" I was being
over-optimistic about the likelihood of duplicates.)

     What you do after discovering the duplication is your problem, no
matter how you manage the map.  If you intend to "copy" one value's
state to the other, it's not clear (from what you've revealed) why
you bother "merging" at all.  If there's some kind of "merge" or
"reconciliation" to be done, it's up to you to do it.

>>> 		TestClass test3 = new TestClass();
>>> 		test3.setVar1(3);
>>> 		if (hm.containsKey(test3.toString())) {
>>> 			test3 = hm.get(test3.toString());
>>> 			test3.setVar2(test3.getVar2() + 55);
>>> 		} else {
>>> 			test3.setVar2(55);
>>> 			hm.put(test3.toString(), test3);
>>> 		}
>>
>>       Similarly here.
> 
> What am I missing here?

     Same suggestion: Ditch containsKey() and let put() tell you
whether the new key is unique or a duplicate, then "copy" or "merge"
or whatever as before.

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-seven days to go.

[toc] | [prev] | [next] | [standalone]


#38524

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-07 14:36 -0400
Message-ID<pkcoql$q0m$1@dont-email.me>
In reply to#38523
On 8/7/2018 2:16 PM, Eric Sosman wrote:
> [...]
>      Using the value returned by put() saves one map lookup in the case
> when the key is already present.  (When I wrote "in half" I was being
> over-optimistic about the likelihood of duplicates.)

      No, I was right, after all.  What you wrote:

	Value newValue = ...;
	String key = ...;
	if (map.containsKey(key)) {
	    Value oldValue = map.get(key);
	    ... merge oldValue and newValue ...
	} else {
	    map.put(key, newValue);
	}

... always searches the map twice.  My suggestion:

	Value newValue = ...;
	String key = ...;
	Value oldValue = map.put(key, newValue);
	if (oldValue != null) {
	    ... merge oldValue and newValue ...
	}

... searches it once, whether the key is present or absent.  One
search instead of two is "in half."

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-seven days to go.

[toc] | [prev] | [next] | [standalone]


#38525

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-07 12:13 -0700
Message-ID<31b0fbe7-3e14-4b60-9779-8435fcd04e22@googlegroups.com>
In reply to#38523
>      It still fails to be antisymmetric:
> 
> 	TestClass obj = new TestClass();
> 	TestClass nil = null;
> 	int one = obj.compareTo(nil);  // yields +ve
> 	int two = nil.compareTo(obj);  // should yield -ve, but throws
> 
> (This discussion seems oddly familiar: Have we had it before?  Ah, yes:
> Google Groups finds a thread from two years ago titled "Why not String
> compare?" and another from one year back titled "What's the best way to
> make a cross string set?"  Both threads discuss implementing Comparable
> and/or Comparator, and the latter touches upon the impossibility of
> implementing Comparable<Object>.  Will this query be an annual event? :)
> 

Ah ok, in this case there should never be a null.  I keep thinking when a method passes in any sort of Object I should account for null as some possibility.  I believe you're suggesting the compareTo method just start with this:
if (compareMe == null) {
throw new Error("don't compare me to a null!");
}

> >>       Alternatively, you might take advantage of the fact that Map::put
> >> returns the old key (if any) associated with its value:
> 
>      Aside: Um, er, Map::put returns the old *value* (if any) associated
> with its *key*, yeah, that's what I meant, yeah, obviously, of course.
> "I misspoke," as the President so eloquently and so often says.
> 

Right?  I believe we both said the same thing and meant something else.  The return value of the put method is the value of the key at the put position (which may be null).  I'm just using my toString() to manually look for a matching object, because I don't otherwise care about the map keys but if there is a matching object, I need to get some values from it, and I don't know how else to get it.  At first I was going to use HashSet, but while it can add() and it can check contains() I didn't see a get value method.

> > 
> > What am I missing here?
> 
>      Same suggestion: Ditch containsKey() and let put() tell you
> whether the new key is unique or a duplicate, then "copy" or "merge"
> or whatever as before.
> 

Ah, I just put 3 objects in my example to show that it stored one, stored a second one separately, and merged another one using the same if condition that stored the second one.  Of course if we change that one condition we change the other to match.  I thought you were saying there's a better way to get the sorted objects out from the last part:

ArrayList<TestClass> al = new ArrayList<>();
al.addAll(hm.values());
Collections.sort(al);
for (TestClass t1 : al) {
	System.out.println(t1.getVar1() + " " + t1.getVar2());
}

If there are no other ideas, thanks for the tip that this code:
if (hm.containsKey(test2.toString())) {
	test2 = hm.get(test2.toString());
	test2.setVar2(test2.getVar2() + 42);
} else {
	test2.setVar2(42);
	hm.put(test2.toString(), test2);
}

works the same as this code (but this should be more efficient).
TestClass temp = hm.put(test2.toString(),test2);
test2.setVar2(temp == null ? 42 : temp.getVar2() + 42);

[toc] | [prev] | [next] | [standalone]


#38526

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-07 16:00 -0400
Message-ID<pkctpm$rf5$1@dont-email.me>
In reply to#38525
On 8/7/2018 3:13 PM, Eric Douglas wrote:
>>       It still fails to be antisymmetric:
>>
>> 	TestClass obj = new TestClass();
>> 	TestClass nil = null;
>> 	int one = obj.compareTo(nil);  // yields +ve
>> 	int two = nil.compareTo(obj);  // should yield -ve, but throws
>>
>> (This discussion seems oddly familiar: Have we had it before?  Ah, yes:
>> Google Groups finds a thread from two years ago titled "Why not String
>> compare?" and another from one year back titled "What's the best way to
>> make a cross string set?"  Both threads discuss implementing Comparable
>> and/or Comparator, and the latter touches upon the impossibility of
>> implementing Comparable<Object>.  Will this query be an annual event? :)
>>
> Ah ok, in this case there should never be a null.

     ... in which case, it's hard to understand why you check for it.

> I keep thinking when a method passes in any sort of Object I should account for null as some possibility.  I believe you're suggesting the compareTo method just start with this:
> if (compareMe == null) {
> throw new Error("don't compare me to a null!");
> }

     I *think* that's all right.  Since nil.compareTo(obj) will throw,
obj.compareTo(nil) must also throw -- but I don't see a requirement
that it throw the same Throwable type.  An `assert' would also be
okay, I think, because (1) if it's enabled and throws AssertionError
that satisfies the requirement to throw, and (2) if it's disabled
you'll get NullPointerException as soon as you try to access the
fields or methods of the null reference.  Objects.requireNonNull()
is yet another possibility.

     What you must not do is what you wrote originally: Pretend the
null reference is to a "null object" and "compare to" that thing.
The null reference is to "no object at all," and you cannot compare
to "no object at all" -- unless "no object at all" can compare itself
to your object, and consistently.

>>>>        Alternatively, you might take advantage of the fact that Map::put
>>>> returns the old key (if any) associated with its value:
>>
>>       Aside: Um, er, Map::put returns the old *value* (if any) associated
>> with its *key*, yeah, that's what I meant, yeah, obviously, of course.
>> "I misspoke," as the President so eloquently and so often says.
> 
> Right?  I believe we both said the same thing and meant something else.  The return value of the put method is the value of the key at the put position (which may be null).

     No.  That's what I wrote initially, and that mis-statement is what
I corrected above.  (Dyxlesia is a dyslexic's self-diangosis.)

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-seven days to go.

[toc] | [prev] | [next] | [standalone]


#38529

FromMartin Gregorie <martin@mydomain.invalid>
Date2018-08-08 08:20 +0000
Message-ID<pke94a$j46$1@news.albasani.net>
In reply to#38519
On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:

> I want to combine and sort objects by key properties and merge their
> secondary properties.  Is there a better way?  This is what I came up
> with..
>
Given your ..and sort... requirement, I'd use a TreeMap rather than a 
HashMap because storing items in key sequence is implicit. In addition, 
its search efficiency rises as the tree gets bigger; if the treemap 
contains 2**23 entries a worst case search only does 23 key comparisons.


-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38530

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-08 06:57 -0400
Message-ID<pkeib2$9pv$1@dont-email.me>
In reply to#38529
On 8/8/2018 4:20 AM, Martin Gregorie wrote:
> On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:
> 
>> I want to combine and sort objects by key properties and merge their
>> secondary properties.  Is there a better way?  This is what I came up
>> with..
>>
> Given your ..and sort... requirement, I'd use a TreeMap rather than a
> HashMap because storing items in key sequence is implicit. In addition,
> its search efficiency rises as the tree gets bigger; if the treemap
> contains 2**23 entries a worst case search only does 23 key comparisons.

     ... except that he sorts on a field of the mapped values,
not on the map keys.  Specifically, if he has two instances with
`var1' values of 2 and 10 they will sort in that order, but
their map keys will sort in the order "10" followed by "2".

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-six days to go.

[toc] | [prev] | [next] | [standalone]


#38531

FromMartin Gregorie <martin@mydomain.invalid>
Date2018-08-08 11:08 +0000
Message-ID<pkeiva$mh4$1@news.albasani.net>
In reply to#38530
On Wed, 08 Aug 2018 06:57:33 -0400, Eric Sosman wrote:

> On 8/8/2018 4:20 AM, Martin Gregorie wrote:
>> On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:
>> 
>>> I want to combine and sort objects by key properties and merge their
>>> secondary properties.  Is there a better way?  This is what I came up
>>> with..
>>>
>> Given your ..and sort... requirement, I'd use a TreeMap rather than a
>> HashMap because storing items in key sequence is implicit. In addition,
>> its search efficiency rises as the tree gets bigger; if the treemap
>> contains 2**23 entries a worst case search only does 23 key
>> comparisons.
> 
>      ... except that he sorts on a field of the mapped values,
> not on the map keys.  Specifically, if he has two instances with `var1'
> values of 2 and 10 they will sort in that order, but their map keys will
> sort in the order "10" followed by "2".

OK - missed that.



-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38532

FromMartin Gregorie <martin@mydomain.invalid>
Date2018-08-08 11:22 +0000
Message-ID<pkejoq$ksf$1@news.albasani.net>
In reply to#38530
On Wed, 08 Aug 2018 06:57:33 -0400, Eric Sosman wrote:

> On 8/8/2018 4:20 AM, Martin Gregorie wrote:
>> On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:
>> 
>>> I want to combine and sort objects by key properties and merge their
>>> secondary properties.  Is there a better way?  This is what I came up
>>> with..
>>>
>> Given your ..and sort... requirement, I'd use a TreeMap rather than a
>> HashMap because storing items in key sequence is implicit. In addition,
>> its search efficiency rises as the tree gets bigger; if the treemap
>> contains 2**23 entries a worst case search only does 23 key
>> comparisons.
> 
>      ... except that he sorts on a field of the mapped values,
> not on the map keys.  Specifically, if he has two instances with `var1'
> values of 2 and 10 they will sort in that order, but their map keys will
> sort in the order "10" followed by "2".

Another thought, seeing that Eric wants to use an integer key, why not 
store the key value in an Integer, which is already Comparable, rather 
than making the class containing the int key Comparable?

This is effectively what I do when manipulating a TreeMap of objects with 
String values as keys. A scan of the class definitions shows that the 
same idea should work for a HashMap. 


-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38533

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-08 07:45 -0400
Message-ID<pkel4d$re6$1@dont-email.me>
In reply to#38532
On 8/8/2018 7:22 AM, Martin Gregorie wrote:
> On Wed, 08 Aug 2018 06:57:33 -0400, Eric Sosman wrote:
> 
>> On 8/8/2018 4:20 AM, Martin Gregorie wrote:
>>> On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:
>>>
>>>> I want to combine and sort objects by key properties and merge their
>>>> secondary properties.  Is there a better way?  This is what I came up
>>>> with..
>>>>
>>> Given your ..and sort... requirement, I'd use a TreeMap rather than a
>>> HashMap because storing items in key sequence is implicit. In addition,
>>> its search efficiency rises as the tree gets bigger; if the treemap
>>> contains 2**23 entries a worst case search only does 23 key
>>> comparisons.
>>
>>       ... except that he sorts on a field of the mapped values,
>> not on the map keys.  Specifically, if he has two instances with `var1'
>> values of 2 and 10 they will sort in that order, but their map keys will
>> sort in the order "10" followed by "2".
> 
> Another thought, seeing that Eric wants to use an integer key, why not
> store the key value in an Integer, which is already Comparable, rather
> than making the class containing the int key Comparable?
> 
> This is effectively what I do when manipulating a TreeMap of objects with
> String values as keys. A scan of the class definitions shows that the
> same idea should work for a HashMap.

     As an extreme case, he might use the object itself as both the
key and value in a Map<TestClass,TestClass>.  I sometimes find this
a useful substitute for a Set<TestClass>, because the Set will tell
me whether an equal item is or isn't present, but will not deliver
the pre-existing item.

     If he were to do this, though, it would be a *very* good idea to
make his `var1' field `final'.  (As things stand it's not required,
but even so: Massive confusion would ensue were it to change.)

     To a related matter, I'm not convinced TreeMap is more efficient
than HashMap-and-sort-afterwards in a situation where the ordering is
needed only after all items have been added.  If anything, I'd imagine
TreeMap would be somewhat less efficient because it expends effort in
keeping itself "always sorted" even while the order is unimportant:
it carefully computes {3} and {1,3} and {1,2,3} and ... {1,2,3,...,N}
even though only the last of these results is required.  I'd save
TreeMap for occasions when the intermediate orderings are to be used
or when "closest match" (as opposed to "present/absent") searches are
needed.

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-six days to go.

[toc] | [prev] | [next] | [standalone]


#38537

FromMartin Gregorie <martin@mydomain.invalid>
Date2018-08-08 14:12 +0000
Message-ID<pketor$sse$1@news.albasani.net>
In reply to#38533
On Wed, 08 Aug 2018 07:45:13 -0400, Eric Sosman wrote:

> On 8/8/2018 7:22 AM, Martin Gregorie wrote:
>> On Wed, 08 Aug 2018 06:57:33 -0400, Eric Sosman wrote:
>> 
>>> On 8/8/2018 4:20 AM, Martin Gregorie wrote:
>>>> On Tue, 07 Aug 2018 06:00:19 -0700, Eric Douglas wrote:
>>>>
>>>>> I want to combine and sort objects by key properties and merge their
>>>>> secondary properties.  Is there a better way?  This is what I came
>>>>> up with..
>>>>>
>>>> Given your ..and sort... requirement, I'd use a TreeMap rather than a
>>>> HashMap because storing items in key sequence is implicit. In
>>>> addition,
>>>> its search efficiency rises as the tree gets bigger; if the treemap
>>>> contains 2**23 entries a worst case search only does 23 key
>>>> comparisons.
>>>
>>>       ... except that he sorts on a field of the mapped values,
>>> not on the map keys.  Specifically, if he has two instances with
>>> `var1' values of 2 and 10 they will sort in that order, but their map
>>> keys will sort in the order "10" followed by "2".
>> 
>> Another thought, seeing that Eric wants to use an integer key, why not
>> store the key value in an Integer, which is already Comparable, rather
>> than making the class containing the int key Comparable?
>> 
>> This is effectively what I do when manipulating a TreeMap of objects
>> with String values as keys. A scan of the class definitions shows that
>> the same idea should work for a HashMap.
> 
>      As an extreme case, he might use the object itself as both the
> key and value in a Map<TestClass,TestClass>.  I sometimes find this a
> useful substitute for a Set<TestClass>, because the Set will tell me
> whether an equal item is or isn't present, but will not deliver the
> pre-existing item.
> 
>      If he were to do this, though, it would be a *very* good idea to
> make his `var1' field `final'.  (As things stand it's not required, but
> even so: Massive confusion would ensue were it to change.)
> 
>      To a related matter, I'm not convinced TreeMap is more efficient
> than HashMap-and-sort-afterwards in a situation where the ordering is
> needed only after all items have been added.  If anything, I'd imagine
> TreeMap would be somewhat less efficient because it expends effort in
> keeping itself "always sorted" even while the order is unimportant: it
> carefully computes {3} and {1,3} and {1,2,3} and ... {1,2,3,...,N} even
> though only the last of these results is required.  I'd save TreeMap for
> occasions when the intermediate orderings are to be used or when
> "closest match" (as opposed to "present/absent") searches are needed.

Actually, red-black trees (which is the tree variant TreeMap uses) is 
surprisingly efficient both for searches and insertions. Some time back 
(1999) I built an implementation (C, not Java) that hit 25,000 lookups[*] 
a second running on a single core Alphaserver chip with half a million 
nodes in the tree and in production was still managing 35,000 lookups a 
second with 100,000,000 nodes in the tree when running on the full holy-
schmoly multicore Alphaserver. 

Nodes were simple: a 13 character string and a 1000 entry bitlist. It 
stored 19 digit international phone numbers, compressing them by storing 
the first 13 digits as a string and using the bitlist position to 
represent the last 3 digits, thus theoretically reducing the actual node 
count by a factor of 1000. This was based on the assumption that the last 
three digits of a phone number are fully used though the rest of the 
number may form a sparse array. Assumption checked with and agreed by 
experts in the field, but proved incorrect in practise - the last three 
digits were also sparse in reality, but still dense enough for this 
representation to save memory space. 

[*] 'Lookup in this application meant "check if the key is present and, 
if not add a new node" Nodes 

The only thing that was slow was startup if the trees had to be rebuilt 
from scratch: that could take 40 minutes. Solved by periodically 
snapshotting the tree's memory space to disk and at shutdown. Starting up 
was now much faster since the trees could be reloaded from disk rather 
than rebuilt from a database.

So, in short, yes I agree that many tree map implementations are slow, 
especially if the input data is in a pathological order, but this does 
not affect to red-black trees, which are self-balancing.
 

-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38534

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-08 05:50 -0700
Message-ID<ac2eee07-9f11-486f-9cc4-a46a07121d87@googlegroups.com>
In reply to#38532
On Wednesday, August 8, 2018 at 7:22:10 AM UTC-4, Martin Gregorie wrote:
> 
> Another thought, seeing that Eric wants to use an integer key, why not 
> store the key value in an Integer, which is already Comparable, rather 
> than making the class containing the int key Comparable?
> 
> This is effectively what I do when manipulating a TreeMap of objects with 
> String values as keys. A scan of the class definitions shows that the 
> same idea should work for a HashMap. 
> 

I'm using objects for grouping and sorting.  For instance we have an object that is a customer address.  It has some 8-10 fields that make up the address (name, street, city, state, zip, country, attention..).  It has some boolean fields that define the purpose of the address (mail to, bill to, ship to).  The fields used in the example in this thread are integers for simplicity, actual fields may contain a collection of different variable types.

I'm using toString() to pass out all values that make the address unique.  This is my map key, so if my ship to source contains an address that matches everything from a mail to source I combine those to get one object that is flagged as both ship to and mail to.  To combine the key must be the string, not the object as both objects would use unique object pointers if you use them as a key.

I'm using compareTo() to define the sort order.  Sort order is computed by those flags then the address fields.  One user wants to see all mail to addresses first, another needs to see ship to addresses first.  I did start by putting a flag in each object to make the objects themselves comparable and use the flag to determine the order (all objects must have the same flag value), though that will look better with a separate Comparator class.

So yeah the TreeMap not only wouldn't work because it sorts by key and I need the objects sorted which would be the values, but it would be less efficient since I don't need them sorted as they're collected, only once after the collection is complete.

[toc] | [prev] | [next] | [standalone]


#38535

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-08 09:23 -0400
Message-ID<pkeqsl$vi3$1@dont-email.me>
In reply to#38534
On 8/8/2018 8:50 AM, Eric Douglas wrote:
> On Wednesday, August 8, 2018 at 7:22:10 AM UTC-4, Martin Gregorie wrote:
>>
>> Another thought, seeing that Eric wants to use an integer key, why not
>> store the key value in an Integer, which is already Comparable, rather
>> than making the class containing the int key Comparable?
>>
>> This is effectively what I do when manipulating a TreeMap of objects with
>> String values as keys. A scan of the class definitions shows that the
>> same idea should work for a HashMap.
>>
> 
> I'm using objects for grouping and sorting.  For instance we have an object that is a customer address.  It has some 8-10 fields that make up the address (name, street, city, state, zip, country, attention..).  It has some boolean fields that define the purpose of the address (mail to, bill to, ship to).  The fields used in the example in this thread are integers for simplicity, actual fields may contain a collection of different variable types.

     A fair amount of running around, several red herrings, and no few
blind alleys might have been avoided had you described the actual
situation to start with.  As it is, we all got sidetracked by issues
that pertain only to the purely synthetic TestClass and friends, issues
that have very little to do with the actual problem.

     Food for thought ...

> I'm using toString() to pass out all values that make the address unique.  This is my map key, so if my ship to source contains an address that matches everything from a mail to source I combine those to get one object that is flagged as both ship to and mail to.  To combine the key must be the string, not the object as both objects would use unique object pointers if you use them as a key.

     (1) I suspect toString() will produce keys that may not be entirely
satisfactory, not unless a good deal of "regularizing" has already been
performed on the data.

	"123 Elm Street"
	"123 Elm St."
	"123 Elm St. Suite 2B"
	"123 Elm Street #2B"
	...

     (2) Concerning "unique object pointers," have you learned about the
equals() and hashCode() methods yet?  ;)

> I'm using compareTo() to define the sort order.  Sort order is computed by those flags then the address fields.  One user wants to see all mail to addresses first, another needs to see ship to addresses first.  I did start by putting a flag in each object to make the objects themselves comparable and use the flag to determine the order (all objects must have the same flag value), though that will look better with a separate Comparator class.

     I recall a thread some time ago that discussed having a "How should
I compare myself?" flag in each object instance, a flag that governs the
way compareTo() works.  IIRC, opinion was pretty much universal that
this would be a Very Bad Idea (even in a variant where the flag was a
static).  Stick with separate Comparators for separate sort orders.

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-six days to go.

[toc] | [prev] | [next] | [standalone]


#38536

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-08 06:47 -0700
Message-ID<e9c51947-c56b-4b35-8e20-2a8882150b86@googlegroups.com>
In reply to#38535
On Wednesday, August 8, 2018 at 9:23:42 AM UTC-4, Eric Sosman wrote:
>      A fair amount of running around, several red herrings, and no few
> blind alleys might have been avoided had you described the actual
> situation to start with.  As it is, we all got sidetracked by issues
> that pertain only to the purely synthetic TestClass and friends, issues
> that have very little to do with the actual problem.
> 
>      Food for thought ...
> 
Trying to write an SSCP as short as possible (no one wants to see 100 lines of code in a message?) with enough code to demonstrate the structure required, which will be used in different variations for different purposes (one to merge people, one to merge places).

> > I'm using toString() to pass out all values that make the address unique.  This is my map key, so if my ship to source contains an address that matches everything from a mail to source I combine those to get one object that is flagged as both ship to and mail to.  To combine the key must be the string, not the object as both objects would use unique object pointers if you use them as a key.
> 
>      (1) I suspect toString() will produce keys that may not be entirely
> satisfactory, not unless a good deal of "regularizing" has already been
> performed on the data.
> 
> 	"123 Elm Street"
> 	"123 Elm St."
> 	"123 Elm St. Suite 2B"
> 	"123 Elm Street #2B"
> 	...
> 
I am aware of that, but hopefully the merging and sorting to get to the data entry where they can enter each address once and check the box for the use cases will help with standards to eliminate some variations.

>      (2) Concerning "unique object pointers," have you learned about the
> equals() and hashCode() methods yet?  ;)
> 
I tried writing an equals method but didn't seem useful if I have to call it manually, was hoping it could be used for such purpose as making the objects themselves the key to a map.  Is hashCode() supposed to be used for this purpose?  I thought that was always supposed to have a generated value unique for every object instance.

> > I'm using compareTo() to define the sort order.  Sort order is computed by those flags then the address fields.  One user wants to see all mail to addresses first, another needs to see ship to addresses first.  I did start by putting a flag in each object to make the objects themselves comparable and use the flag to determine the order (all objects must have the same flag value), though that will look better with a separate Comparator class.
> 
>      I recall a thread some time ago that discussed having a "How should
> I compare myself?" flag in each object instance, a flag that governs the
> way compareTo() works.  IIRC, opinion was pretty much universal that
> this would be a Very Bad Idea (even in a variant where the flag was a
> static).  Stick with separate Comparators for separate sort orders.
> 
Old habits of how things were coded a decade or two ago, being easier to code what is known rather than develop the new syntax combined with writing Java in a third party language that is Java integrated rather than the Java language itself means not every method may be available ie no lambdas there.

So this is what I have now for an example:
	private static class TestClass {
		private String f1 = "";
		private String f2 = "";
		private boolean var1;
		private boolean var2;

		public String getMergeValue() {
			return f1 + f2;
		}

		public String getSortValue(final int sortBy) {
			switch (sortBy) {
			case 1:
				return (var1 == Boolean.FALSE) + f1 + f2;
			default:
				return (var2 == Boolean.FALSE) + f1 + f2;
			}
		}

		@Override
		public String toString() {
			return f1 + " " + f2 + " " + String.valueOf(var1) + " " + String.valueOf(var2);
		}

		public void setF1(String value) {
			f1 = value;
		}

		public String getF1() {
			return f1;
		}

		public void setF2(String value) {
			f2 = value;
		}

		public String getF2() {
			return f2;
		}

		public void setVar1(boolean value) {
			var1 = value;
		}

		public boolean getVar1() {
			return var1;
		}

		public void setVar2(boolean value) {
			var2 = value;
		}

		public boolean getVar2() {
			return var2;
		}
	}

	public static class ObjectCompare implements Comparator<TestClass> {
		private int sortOrder = 1;

		public ObjectCompare(final int sortBy) {
			sortOrder = sortBy;
		}

		@Override
		public int compare(TestClass cmpOne, TestClass cmpTwo) {
			if (cmpOne == null || cmpTwo == null) {
				throw new Error("cannot compare null objects");
			}
			return cmpOne.getSortValue(sortOrder).compareTo(cmpTwo.getSortValue(sortOrder));
		}

		public int getSortOrder() {
			return sortOrder;
		}

		public void setSortOrder(final int value) {
			sortOrder = value;
		}

	}

	public static void main(final String[] args) {
		HashMap<String, TestClass> hm = new HashMap<>();
		TestClass temp;

		TestClass test1 = new TestClass();
		test1.setF1("one");
		test1.setF2("first");
		test1.setVar1(true);
		temp = hm.put(test1.getMergeValue(), test1);
		test1.setVar2(temp == null ? test1.getVar2() : Boolean.logicalOr(test1.getVar2(), temp.getVar2()));

		TestClass test2 = new TestClass();
		test2.setF1("two");
		test2.setF2("second");
		test2.setVar2(true);
		temp = hm.put(test2.getMergeValue(), test2);
		test2.setVar1(temp == null ? test2.getVar1() : Boolean.logicalOr(test2.getVar1(), temp.getVar1()));

		TestClass test3 = new TestClass();
		test3.setF1("one");
		test3.setF2("first");
		test3.setVar2(true);
		temp = hm.put(test3.getMergeValue(), test3);
		test3.setVar1(temp == null ? test3.getVar1() : Boolean.logicalOr(test3.getVar1(), temp.getVar1()));

		TestClass test4 = new TestClass();
		test4.setF1("three");
		test4.setF2("third");
		test4.setVar1(true);
		temp = hm.put(test4.getMergeValue(), test4);
		test4.setVar2(temp == null ? test4.getVar2() : Boolean.logicalOr(test4.getVar2(), temp.getVar2()));

		ArrayList<TestClass> al = new ArrayList<>();
		al.addAll(hm.values());
		System.out.println("Sorting by value 1");
		Collections.sort(al, new ObjectCompare(1));
		for (TestClass t1 : al) {
			System.out.println(t1.toString());
		}
		System.out.println("Sorting by value 2");
		Collections.sort(al, new ObjectCompare(2));
		for (TestClass t1 : al) {
			System.out.println(t1.toString());
		}
	}

[toc] | [prev] | [next] | [standalone]


#38538

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2018-08-08 10:31 -0400
Message-ID<pkeust$pia$1@dont-email.me>
In reply to#38536
On 8/8/2018 9:47 AM, Eric Douglas wrote:
> On Wednesday, August 8, 2018 at 9:23:42 AM UTC-4, Eric Sosman wrote:
>> [...]
>>       (2) Concerning "unique object pointers," have you learned about the
>> equals() and hashCode() methods yet?  ;)
>>
> I tried writing an equals method but didn't seem useful if I have to call it manually, was hoping it could be used for such purpose as making the objects themselves the key to a map.  Is hashCode() supposed to be used for this purpose?  I thought that was always supposed to have a generated value unique for every object instance.

     Are you trolling?  You've been participating in this forum for
upwards of three years, and last year you said you'd been writing
Java "for probably about 10 years" -- and we're supposed to believe you
don't know what equals() and hashCode() are for?

     Benefit of the doubt: I guess it's just barely possible that after
eleven-ish (claimed) or three-plus (shown) years of Java involvement
you might actually be unfamiliar with the basics.  You have shown more
than once that your grasp of Java concepts is less than firm, and I have
speculated that you may be trying to write Java by "faking it" with an
extensive knowledge of other languages.  (I still consider that the most
likely explanation for your blunders, although the Troll Hypothesis is
beginning to gain credibility.)  But just in case you're not trolling,

	F E R   P E T E ' S   S A K E ,   R E A D   A   B O O K !

-- 
esosman@comcast-dot-net.invalid
Eight hundred ninety-six days to go.

[toc] | [prev] | [next] | [standalone]


#38540

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-08-08 08:24 -0700
Message-ID<98fc8aac-6b70-4c34-873d-b7c59dfb2fb2@googlegroups.com>
In reply to#38538
On Wednesday, August 8, 2018 at 10:32:06 AM UTC-4, Eric Sosman wrote:
> >> [...]
> >>       (2) Concerning "unique object pointers," have you learned about the
> >> equals() and hashCode() methods yet?  ;)
> >>
> > I tried writing an equals method but didn't seem useful if I have to call it manually, was hoping it could be used for such purpose as making the objects themselves the key to a map.  Is hashCode() supposed to be used for this purpose?  I thought that was always supposed to have a generated value unique for every object instance.
> 
>      Are you trolling?  You've been participating in this forum for
> upwards of three years, and last year you said you'd been writing
> Java "for probably about 10 years" -- and we're supposed to believe you
> don't know what equals() and hashCode() are for?
> 
>      Benefit of the doubt: I guess it's just barely possible that after
> eleven-ish (claimed) or three-plus (shown) years of Java involvement
> you might actually be unfamiliar with the basics.  You have shown more
> than once that your grasp of Java concepts is less than firm, and I have
> speculated that you may be trying to write Java by "faking it" with an
> extensive knowledge of other languages.  (I still consider that the most
> likely explanation for your blunders, although the Troll Hypothesis is
> beginning to gain credibility.)  But just in case you're not trolling,
> 
> 	F E R   P E T E ' S   S A K E ,   R E A D   A   B O O K !
> 

I have neither time nor money to take a class in Java.  I graduated college in 1996, Java wasn't a thing yet.  I have coded in several languages, starting with COBOL, now primarily in a Business BASIC language which is now a hybrid Java integrated with a custom interpreter which can create Java objects using not quite Java syntax.  We started an in house Java API somewhere around 2008.

I taught myself most everything I know from the Oracle documentation.  The documentation on Object seems a bit vague, as it says hashCode() is typically an integer representation of the internal address of the object, and if equals returns true then the hashCode of the 2 instances must match but if equals returns false they don't have to match.  I didn't see in there exactly where or how equals or hashCode are used, so 1) I wasn't sure which of these methods might be called by the Oracle methods (Map.put?) and 2) if it's a good idea to customize the hashCode.  Should hashCodes be unique to each object instance, or should they return the same value if as in this example a ship to address object and a bill to address object refer to the same physical address?

[toc] | [prev] | [next] | [standalone]


#38558

FromRobert Klemme <shortcutter@googlemail.com>
Date2018-08-14 14:06 +0200
Message-ID<ftfuunF4g0lU1@mid.individual.net>
In reply to#38534
On 08.08.2018 16:50, Stefan Ram wrote:
> Eric Douglas <e.d.programmer@gmail.com> writes:
>> I'm using toString() to pass out all values that make the
>> address unique.  This is my map key, so if my ship to source
>> contains an address that matches everything from a mail to
>> source I combine those to get one object that is flagged as
>> both ship to and mail to.  To combine the key must be the
>> string, not the object as both objects would use unique
>> object pointers if you use them as a key.
> 
>    A class should be written so that its objects meaningfully
>    represent an entity, and the standard methods like
>    »compareTo« and »equals« should implement the natural
>    ordering and equality properties of such an entity observing
>    all the contracts from java.lang.Object and Comparable.
> 
>    These standard methods should not be tuned to "work" for a
>    specific use case (Map) when this compromises their natural
>    semantics or the standard semantics and contracts of the JDK
>    (java.lang.Object, java.lang.Comparable).
> 
>    If such an entity then is to be used in an application where
>    a specific order or merge behavior is required that is /not/
>    implemented by the normal ordering and equality behavior of
>    such an entity, one should not compromise the standard
>    methods of this entity by modifying them for a specific use
>    case, but instead use something like an adapter or some such.
> 
>    For example, an object might have a method »getKey« that
>    returns an object that is intended to be used as a key for
>    the object in certain maps. It is not obvious whether a
>    string is the best type for such a key.
> 
>    »toString« should return a meaningful string representation
>    of an object for a human seeing its value in error or log
>    messages. It is not intended to provide a key to be used in maps.

I could not agree more.  A few more thoughts:

It seems the class design can be improved, e.g. by separating out the 
"8-10 fields that make up the address" in a class of its own.  That 
could have proper hashCode() and equals() implementations and maybe a 
default order (once Eric catches up on the basics).

I also think the flags should be removed altogether (basically leading 
to the same result as above) since the sort order is determined by the 
user ("One user wants to see all mail to addresses first, another needs 
to see ship to addresses first."), i.e. it is not part of the 
(presumably persistent) data but rather of the _use_ of it (i.e. viewing 
on the screen or processing it for some purpose).  There should 
definitively be a Comparable instance that can be used as a Map key for 
the different orders supported.  Definitively use specific classes for 
keys instead of abusing toString() for this!

Cheers

	robert


-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.java.programmer


csiph-web