jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • groovy
  • GROOVY-3992

Add a reverse method to Map

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Improvement Improvement
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 1.7.2, 1.8-beta-1
  • Component/s: None
  • Labels:
    None

Description

It would be nice to be able to reverse the order of a map without running collect on it first. For example,

def foo = ["string1":1, "string2":2, "string3":3]
println foo.sort {it.value}.collect{it}.reverse() // <-- this works
//println foo.sort {it.value}.reverse() // <-- this is what I propose

This is, of course, a simplistic example for which there are workarounds, like
foo.sort {-it.value}
but I could imagine other potential uses for this method.

Issue Links

is related to

New Feature - A new feature of the product, which has yet to be developed. GROOVY-2597 Map or Property Sort

  • Minor - Minor loss of function, or other problem where easy workaround is present.
  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
blackdrag blackdrag added a comment - 11/Jan/10 2:53 PM

A Map does not imply any order on the values. You see an input order because we use a LinkedHashMap. If it were a TreeMap you would see a different order. You get a sorting in here because of your call to sort, but your collect then returns a list. So your reverse ends up with a list too... You want a list in the end?

Show
blackdrag blackdrag added a comment - 11/Jan/10 2:53 PM A Map does not imply any order on the values. You see an input order because we use a LinkedHashMap. If it were a TreeMap you would see a different order. You get a sorting in here because of your call to sort, but your collect then returns a list. So your reverse ends up with a list too... You want a list in the end?
Hide
Permalink
Keegan Witt added a comment - 11/Jan/10 5:04 PM

Sorry if I confused. You are correct, a Map itself doesn't imply order. But since you've used LinkedHashMap, there is an order implied. I had to use collect because List has reverse, but not Map. So, what I am proposing is a method that is called on the LinkedHashMap that returns a LinkedHashMap, but in reverse of its original order. Thus, this would run:

def foo = [:]
foo.put(new String("string1"), 1)
foo.put(new String("string2"), 2)
foo.put(new String("string3"), 3)
def bar = foo.reverse()
assert bar == ["string3":3, "string2":2, "string1":1]
assert bar.getClass().toString() == "class java.util.LinkedHashMap"

Show
Keegan Witt added a comment - 11/Jan/10 5:04 PM Sorry if I confused. You are correct, a Map itself doesn't imply order. But since you've used LinkedHashMap, there is an order implied. I had to use collect because List has reverse, but not Map. So, what I am proposing is a method that is called on the LinkedHashMap that returns a LinkedHashMap, but in reverse of its original order. Thus, this would run: def foo = [:] foo.put(new String("string1"), 1) foo.put(new String("string2"), 2) foo.put(new String("string3"), 3) def bar = foo.reverse() assert bar == ["string3":3, "string2":2, "string1":1] assert bar.getClass().toString() == "class java.util.LinkedHashMap"
Hide
Permalink
blackdrag blackdrag added a comment - 12/Jan/10 1:56 AM

so more or less LinkedHashMap#reverse and no Map#reverse, ok.

Show
blackdrag blackdrag added a comment - 12/Jan/10 1:56 AM so more or less LinkedHashMap#reverse and no Map#reverse, ok.
Hide
Permalink
blackdrag blackdrag added a comment - 12/Jan/10 2:02 AM

But there are two things here... first the assert does not test the order. [a:1,b:2] and [b:2,a:1] are equal maps. They are not equal according to the input order, but have the same elements. That is unlike lists, which are order sensitive. So your testcase above won't help much. to test the order you ave to iterate over bot maps and compare that both maps have equal elements at the same position.

The other thing: input order != key or value based ordering. You tend to order the maps in lexical order depending on the key in your examples. That is why your code kind of works in the end. But instead of [a:1,b:2,c:3] I can have also [a:1,c:3,b:2] and then the reverse would of course not be [c:3,b:2,a:1] but [b:2,c:3,a:1]

Show
blackdrag blackdrag added a comment - 12/Jan/10 2:02 AM But there are two things here... first the assert does not test the order. [a:1,b:2] and [b:2,a:1] are equal maps. They are not equal according to the input order, but have the same elements. That is unlike lists, which are order sensitive. So your testcase above won't help much. to test the order you ave to iterate over bot maps and compare that both maps have equal elements at the same position. The other thing: input order != key or value based ordering. You tend to order the maps in lexical order depending on the key in your examples. That is why your code kind of works in the end. But instead of [a:1,b:2,c:3] I can have also [a:1,c:3,b:2] and then the reverse would of course not be [c:3,b:2,a:1] but [b:2,c:3,a:1]
Hide
Permalink
blackdrag blackdrag added a comment - 12/Jan/10 2:03 AM

what do others think?

Show
blackdrag blackdrag added a comment - 12/Jan/10 2:03 AM what do others think?
Hide
Permalink
Paul King added a comment - 13/Jan/10 5:19 AM

We have known and easy to use workarounds. I would like to see some more compelling examples.

Show
Paul King added a comment - 13/Jan/10 5:19 AM We have known and easy to use workarounds. I would like to see some more compelling examples.
Hide
Permalink
Paul King added a comment - 12/Mar/10 6:31 PM - edited

No further compelling examples given. Assuming workarounds are sufficient.
But adding a reverseEach() method for Map which might help with some of
what you are after.

Also, see GROOVY-2597 which asks for a Map/Properties sort capability.
Sorting in reverse order would yield what you are after.

Show
Paul King added a comment - 12/Mar/10 6:31 PM - edited No further compelling examples given. Assuming workarounds are sufficient. But adding a reverseEach() method for Map which might help with some of what you are after. Also, see GROOVY-2597 which asks for a Map/Properties sort capability. Sorting in reverse order would yield what you are after.
Hide
Permalink
Paul King added a comment - 13/Mar/10 5:03 AM

Added reverseEach() with the following functionality:

TreeMap map = [c:2, b:3, a:1]
String result1 = "", result2 = ""
map.each{ k, v -> result1 += "$k$v " }
assert result1 == "a1 b3 c2 "
map.reverseEach{ e -> result2 += "$e.key$e.value " }
assert result2 == "c2 b3 a1 "
Show
Paul King added a comment - 13/Mar/10 5:03 AM Added reverseEach() with the following functionality:
TreeMap map = [c:2, b:3, a:1]
String result1 = "", result2 = ""
map.each{ k, v -> result1 += "$k$v " }
assert result1 == "a1 b3 c2 "
map.reverseEach{ e -> result2 += "$e.key$e.value " }
assert result2 == "c2 b3 a1 "
Hide
Permalink
Paul King added a comment - 13/Mar/10 5:26 AM

Some examples - also showing reversing a TreeMap:

def stringify = { m ->  m.collect{ k, v -> "$k$v" }.join(' ') }

def map1 = [c:2, b:3, a:1]
def string1 = "", string2 = ""
map1.each{ string1 += "${it.key}${it.value} " }
map1.reverseEach{ string2 += "${it.key}${it.value} "}
assert string1 == 'c2 b3 a1 '
assert string2 == 'a1 b3 c2 '

def map2 = new TreeMap(map1)
assert stringify(map2) == 'a1 b3 c2'

def map3 = new TreeMap(Collections.reverseOrder())
map3.putAll(map2)
assert stringify(map3) == 'c2 b3 a1'

def map4 = map2.descendingMap()
assert stringify(map4) == 'c2 b3 a1'
Show
Paul King added a comment - 13/Mar/10 5:26 AM Some examples - also showing reversing a TreeMap:
def stringify = { m ->  m.collect{ k, v -> "$k$v" }.join(' ') }

def map1 = [c:2, b:3, a:1]
def string1 = "", string2 = ""
map1.each{ string1 += "${it.key}${it.value} " }
map1.reverseEach{ string2 += "${it.key}${it.value} "}
assert string1 == 'c2 b3 a1 '
assert string2 == 'a1 b3 c2 '

def map2 = new TreeMap(map1)
assert stringify(map2) == 'a1 b3 c2'

def map3 = new TreeMap(Collections.reverseOrder())
map3.putAll(map2)
assert stringify(map3) == 'c2 b3 a1'

def map4 = map2.descendingMap()
assert stringify(map4) == 'c2 b3 a1'

People

  • Assignee:
    Paul King
    Reporter:
    Keegan Witt
Vote (0)
Watch (0)

Dates

  • Created:
    11/Jan/10 2:04 PM
    Updated:
    07/Apr/10 11:45 PM
    Resolved:
    13/Mar/10 5:03 AM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.