Note that there are some explanatory texts on larger screens.

plurals
  1. POFirst N values of a Map<K, V> sorted by value
    primarykey
    data
    text
    <p>I have a list of Strings. I want to evaluate each string based on a function that returns a double. Then I want the first 5 strings, based on their calculated values. If there are fewer than 5, I want all of them (in order). Let's say the strings are chemical compounds and the function computes the mass. The function is computationally expensive; I need to evaluate it once per string. (I'm just making up data here, though.)</p> <pre><code>H2O =&gt; 18.5 C12H11O22 =&gt; 109.1 HeNe =&gt; 32.0 H2SO4 =&gt; 54.37 HCl =&gt; 19.11 4FeO3 =&gt; 82.39 Xe6 =&gt; 281.9 </code></pre> <p>The program should return the first five strings arranged in order by their respective values. For this sample data: <code>H20, HCl, HeNe, H2SO4, 4FeO3</code>. Actually, I don't really care about the order; I just need the five lowest in any order.</p> <p>I thought about how I'd do this in Perl. It's just a few lines:</p> <pre><code>foreach $s (@str) { $strmap{$s} = f($s); } @sorted = sort { $strmap{$a} &lt;=&gt; $strmap{$b} } keys %strmap; return @sorted[0, 4] </code></pre> <p>But I need to do it in Java. And it's driving me crazy.</p> <p>First I tried populating a <code>HashMap&lt;String, Double&gt;</code>, then using <code>Collections.sort</code> with a custom comparator, just like the Perl version. But scoping on the Comparator prevented it from referring to the HashMap to look up the values.</p> <p>Then I tried a <code>TreeMap&lt;String, Double&gt;</code>, but it only sorts by key and no amount of coercing could get it to order the entries by value.</p> <p>So I tried a <code>TreeMap&lt;Double, String&gt;</code>. It will discard entries with the same Double. However, the likelihood of having Strings that map to the same Double is low, so I pressed forward. Adding the entries to the TreeMap is no problem, but I ran into issues trying to extract the values from it.</p> <p>TreeMap supplies a method called <code>subMap</code>, but its parameters are the keys that delimit the subset. I don't know what they are; I just want the first five of them. So I tried using the <code>values</code> method to get all the values out of the TreeMap, hoping they'd be in order. Then I can just get the first ten.</p> <pre><code>ArrayList&lt;String&gt; strs = (ArrayList&lt;String&gt;)(treemap.values()); return new ArrayList&lt;String&gt;(strs.subList(0, 5)); </code></pre> <p>Nope. Runtime error: cannot cast TreeMap$Values to ArrayList.</p> <pre><code>List&lt;String&gt; strs = (List&lt;String&gt;)(treemap.values()); return new ArrayList&lt;String&gt;(strs.subList(0, 5)); </code></pre> <p>Same. Runtime error trying to do the cast. OK, let's just assign to a Collection...</p> <pre><code>Collection&lt;String&gt; strs = treemap.values(); return new ArrayList&lt;String&gt;(strs.subList(0, 5)); </code></pre> <p>Sorry, <code>subList</code> isn't a method of Collection.</p> <pre><code>Collection&lt;String&gt; strs = treemap.values(); ArrayList&lt;String&gt; a = new ArrayList&lt;String&gt;(strs); return new ArrayList&lt;String&gt;(a.subList(0, 5)); </code></pre> <p>Finally, something that works! But two extra data structures just to get the first five elements? And I'm not too wild about using Double as the key for TreeMap.</p> <p>Is there a better solution?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload