I have a list of input strings of the form "code-marks"
For example,
1001-40
1002-54
1003-23
1001-45
1004-60
Expected output:
1004-60
1002-54
1001-45
1003-23
If the values are repeated (like 1001) the latest is used and also need to be sorted.
My first bet was to use TreeMap but it would pose a problem of sorting based on values which is impossible.
Scanner in = new Scanner(System.in);
SortedMap<Integer, Integer> map = new TreeMap<Integer, Integer>(new Comparator<Integer>() {
public int compare(Integer i, Integer j) {
return(j.compareTo(i));
}
});
int i=0;
while(i<5)
{
String[] s = in.next().split("\\-");
map.put(Integer.parseInt(s[0]),Integer.parseInt(s[1]));
i++;
}
// Get a set of the entries
Set set = map.entrySet();
// Get an iterator
Iterator itr = set.iterator();
// Display elements
while(itr.hasNext()) {
Map.Entry me = (Map.Entry)itr.next();
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
What is the best approach to this situation?
I stole code from the link #Pshemo posted and then setup your data as part of the main along with a simulated unit test. Code first then output.
Code
import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeMap;
/**
* Group of code marks
*/
public class CodeMarks {
/**
* Keep track of the most recently added suffix (value) by prefix (key)
*/
HashMap<Integer, Integer> codeMarks = new HashMap<Integer, Integer>();
/**
* Add a code mark (i.e. ####-##) to the group.
* If same prefix already exists overwrite.
*
* #param codeMark
*/
public void add(String codeMark) {
// add some validation here
String[] pieces = codeMark.split("\\-");
Integer prefix = Integer.parseInt(pieces[0]);
Integer suffix = Integer.parseInt(pieces[1]);
codeMarks.put(prefix, suffix);
}
/**
* Sort code marks in descending suffix order.
*/
Comparator<Integer> comparator = new Comparator<Integer>() {
#Override
public int compare(Integer prefixA, Integer prefixB) {
Integer suffixA = codeMarks.get(prefixA);
Integer suffixB = codeMarks.get(prefixB);
if (suffixB.equals(suffixA))
return prefixB.compareTo(prefixA);
else
return suffixB.compareTo(suffixA);
}
};
/**
* Output all code marks in descending suffix order
*/
public String toString() {
TreeMap<Integer,Integer> sorted_map = new TreeMap<Integer,Integer>(comparator);
sorted_map.putAll(codeMarks);
StringBuffer output = new StringBuffer();
for (Integer prefix : sorted_map.keySet()) {
Integer suffix = sorted_map.get(prefix);
output.append(prefix + "-" + suffix + "\n");
}
return output.toString();
}
public static void main(String args[]) {
CodeMarks cm = new CodeMarks(){{
add("1001-40");
add("1002-54");
add("1003-23");
add("1001-45");
add("1004-60");
}};
String expected =
"1004-60\n" +
"1002-54\n" +
"1001-45\n" +
"1003-23\n";
String actual = cm.toString();
System.out.println(actual);
System.out.println("actual.equals(expected): " + actual.equals(expected));
}
}
Output
1004-60
1002-54
1001-45
1003-23
actual.equals(expected): true
I would simply use a HashMap<Code, CodeMark> to eliminate duplicate codes, then put all the values inside a List<CodeMark>, and sort this list by mark in descending order.
You can use HashMap<Integer,Integer> simply and then sort that according to their values:
public LinkedHashMap<Integer,Integer> sortHashMapByValues(HashMap<Integer,Integer> passedMap) {
List<Integer> mapKeys = new ArrayList<Integer>(passedMap.keySet());
List<Integer> mapValues = new ArrayList<Integer>(passedMap.values());
Collections.sort(mapValues);
Collections.sort(mapKeys);
LinkedHashMap<Integer,Integer> sortedMap =
new LinkedHashMap<Integer,Integer>();
Iterator valueIt = mapValues.iterator();
while (valueIt.hasNext()) {
Object val = valueIt.next();
Iterator keyIt = mapKeys.iterator();
while (keyIt.hasNext()) {
int key = (Integer)keyIt.next();
int comp1 = (Integer)passedMap.get(key);
int comp2 = (Integer)val;
if (comp1 == comp2){
passedMap.remove(key);
mapKeys.remove(key);
sortedMap.put(key,(Integer) val);
break;
}
}
}
return sortedMap;
}
Related
I have two ArrayLists.
List of dates
List of respective data.
Both are synchronized. I sometimes have more than one data on a same date. I need to create two lists: unique dates and the data (averaged) respectively. So far, I have tried the following methods
int i = 1;
for(int it =0; it < predatetime.size() - 1; it++){
//Compare each element with the next one
if(predatetime.get(it+1) == predatetime.get(it)){
i++;
weight = preweight.get(it+1) + weight;
//If equal, add weights and increment a divisor for averaging
}
else { //if not equal, add to the new lists
if(it == predatetime.size() - 2){ //if the last element is not equal to its previous one, just add it to the list
newDateTime.add(predatetime.get(it+1));
newWeight.add(preweight.get(it+1));
break;
}
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
weight = preweight.get(it+1); //re-initialize variables
i = 1;
}
if(it == predatetime.size() - 2){
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
}
}
There are a lot of problems with this code.
If the list has only one element, it fails. (I know I can write 2 more lines to care of this). Is there a better way to do this?
I know there are similar questions on this website, but still I'm unable to resolve the problem.
This is the full solution
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class CustomList {
public static void main(String[] args) {
ArrayList<String> date = new ArrayList<>();
date.add("1");
date.add("2");
date.add("2");
date.add("3");
System.out.println(date);
ArrayList<Integer> value = new ArrayList<>();
value.add(1);
value.add(2);
value.add(4);
value.add(3);
System.out.println(value);
new MyCls().createList(date, value);
}
}
class MyCls {
ArrayList uniqueDate = new ArrayList<String>();
ArrayList averageValue = new ArrayList<Integer>();
LinkedHashMap store = new LinkedHashMap<String, CountEntry>();
class CountEntry {
int value;
int count;
CountEntry() {
}
CountEntry(int v, int c) {
value = v;
count = c;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public void createList(ArrayList<String> date, ArrayList<Integer> value) {
for (int i = 0; i < date.size(); i++) {
CountEntry tmp = (CountEntry) store.get(date.get(i));
if (tmp == null) {
store.put(date.get(i), new CountEntry(value.get(i), 1));
} else {
int tmpVal = tmp.getValue();
int tmpCount = tmp.getCount();
store.put(date.get(i), new CountEntry(value.get(i) + tmpVal, ++tmpCount));
}
}
ArrayList<String> uniqueDate = new ArrayList<String>(store.keySet());
ArrayList<CountEntry> tempAvgList = new ArrayList<CountEntry>(store.values());
for (CountEntry ce : tempAvgList) {
averageValue.add(ce.getValue() / ce.getCount());
}
System.out.println("Output");
System.out.println(uniqueDate);
System.out.println(averageValue);
}
}
/*
OUTPUT Snap:
[1, 2, 2, 3]
[1, 2, 4, 3]
Output
[1, 2, 3]
[1, 3, 3]
*/
If you try to make your list elements unique why you not try to convert the list to set collection
Set<Foo> foo = new HashSet<Foo>(myList);
Why not create a Map instead with the dates as the key and have the value as a list. This will allow you to keep the dates unique, at the same allow you to have your data as a list.
Map<String, ArrayList<myData>> myMap = new HashMap<String, ArrayList<myData>>();
Then you can just find if your key exists, if it does add it to the array list by using the key to identify the correct list. If it doesnt exist it, add it to the map
Thanks to #Rambler and #JulianGurung, I created a HashMap and it works
HashMap<Integer, Float> hm = new HashMap<Integer,Float>();
int occurance = 0;
float weight = 0;
hm.put(predatetime.get(0), 0f); //initialize with the first value
for(Map.Entry m : hm.entrySet()){
for( int it = 0; it < predatetime.size(); it++){
if(m.getKey() == predatetime.get(it)){
weight = (Float) m.getValue() + preweight.get(it); //Sum all the same data in order to avg later
hm.put(predatetime.get(it), weight);
occurance++;
}
else{ //if it is not equal, add the new element to the map
hm.put(predatetime.get(it), preweight.get(it));
}
}
weight = weight / occurance;
hm.put((Integer) m.getKey(), weight);
weight = 0;
occurance = 0;
}
I need to sort List by Map, using key of Map. Firstly look at code, afterwards listen to me. I would like to sort List by Key, and after by Value. The result after all should be the following(return only value in List):
/* The result(List):
str3
str1
str2
str4 */
--
List<String> list = ArrayList<>();
list.add("str1");
list.add("str1");
list.add("str3");
list.add("str4"); .......
Map<String, Integer> counts = new HashMap<>();
for (String item:list) {
Integer count = counts.get(item);
if (count == null) {
count = 1;
} else {
count = count + 1;
}
counts.put(item, count);
}
for (Entry<String, Integer> entry : counts.entrySet()) {
System.out.println(entry.getValue() + " " + entry.getKey());
}
--
/* The result:
2 str1
3 str2
1 str3
3 str4 */
Make a custom comparator:
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String left, String right) {
return Integer.compare(counts.get(left), counts.get(right));
}
});
Note that you need to make counts final for this to work.
Running this on your example:
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("str1");
list.add("str2");
list.add("str3");
list.add("str4");
final Map<String, Integer> counts = new HashMap<>();
counts.put("str1", 2);
counts.put("str2", 3);
counts.put("str3", 1);
counts.put("str4", 3);
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String left, String right) {
return Integer.compare(counts.get(left), counts.get(right));
}
});
System.out.println(list);
}
}
Yields:
[str3, str1, str2, str4]
When you want to read the Mapentries sorted by key, you could use a Treemap.
Buy maybe you can rephrase the question, it's not very clear what the result should be.
I have a TreeMap in which I have stored some values. The map is sorted using the values, from highest to lowest. Now I want print out the contents of the TreeMap with their various indices.
If I have the following pairs in the map :
("Andrew", 10),
("John", 5),
("Don",9),
("Rolex", 30),
("Jack", 10),
("Dan",9)
I want to print out:
Rolex, 30 , 1
Jack, 10, 2
Andrew, 10, 2
Dan, 9, 4
Don, 9, 4
John, 5, 6.
This is what I've been trying but it doesn't seem to work well:
/**
*
* #author Andrew
*/
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res!= 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos = 1;
for(int i = 0; i<names.size();){
try{
int y = i+1;
if(scores.get(i).equals(scores.get(y))){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos));
//pos++;
i++;
continue;
} else{
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos++));
}
i++;
} catch(IndexOutOfBoundsException e) {}
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
First of all, Why are you catching that IndexOutOfBoundsException and doing nothing with it? if you run that you'll get that exception thrown (and I thing you already know it) the problem is in your algorithm inside the last "for" loop. I shouldn't give you the solution, but wth... at least you did some effort to make it run, so this is a more less working version:
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res != 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos;
int posBis = 0;
String lastScore = "";
for(int i = 0; i<names.size(); i++){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
if(i == 0 || !lastScore.equals(scores.get(i))) {
pos = i + 1;
posBis = pos;
} else {
pos = posBis;
}
System.out.println("Position: "+ String.valueOf(pos));
lastScore = (String)scores.get(i);
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
Your SortedSet is the wrong way to go about this. You can see in your Comparator that it gets a bit messy when both values have to be looked up by the same key then you've got this messy (and incorrect) return res != 0 ? res : 1 (the 1 should really be e1.getKey().compareTo(e2.getKey()) rather than always returning 1).
A better way to go about this would be to just sort the keys yourself in a List, rather than creating a separate SortedSet. This way you don't have to worry about duplicate sorting values.
You can also abstract out the Comparator stuff a little, to make it more reusable in other code later, if you need it.
import java.util.*;
public class PrintSomething {
public static <T extends Comparable<T>> Comparator<T> reverseComparator(final Comparator<T> oldComparator) {
return new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
return oldComparator.compare(o2, o1);
}
};
}
public static <K,V extends Comparable<V>> Comparator<K> keyedComparator(final Map<K,V> lookup) {
return new Comparator<K>() {
#Override
public int compare(K o1, K o2) {
return lookup.get(o1).compareTo(lookup.get(o2));
}
};
}
public static void main(String[] args) {
Map<String, Integer> mm = new HashMap<>();
mm.put("Andrew", 10);
mm.put("John", 5);
mm.put("Don", 9);
mm.put("Rolex", 30);
mm.put("Jack", 10);
mm.put("Dan", 9);
Comparator<String> comparator = reverseComparator(keyedComparator(mm));
List<String> keys = Arrays.asList(mm.keySet().toArray(new String[mm.size()]));
//Collections.sort(keys); // optional, if you want the names to be alphabetical
Collections.sort(keys, comparator);
int rank = 1, count = 0;
Integer lastVal = null;
for (String key : keys) {
if (mm.get(key).equals(lastVal)) {
count++;
} else {
rank += count;
count = 1;
}
lastVal = mm.get(key);
System.out.println(key + ", " + mm.get(key) + ", " + rank);
}
}
}
In general things like SortedSet make more sense when you need to keep the data itself sorted. When you just need to process something in a sorted manner one time they're usually more trouble than they're worth. (Also: is there any reason why you're using a TreeMap? TreeMaps sort their keys, but not by value, so in this case you're not taking advantage of that sorting. Using a HashMap is more common in that case.)
You do a lot of work with the iterator, calling toString(), then splitting the results. And your Comparator is extra work too. Stay with a Map on both sides - you can use keys() and values() more directly, and let Java do the sorting for you. Most of your above code can be replaced with: (for clarity, I changed your name "mm" to "originalMap")
Map<Integer, String> inverseMap = new TreeMap<Integer, String>();
for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
inverseMap.put(entry.getValue(), entry.getKey());
}
Now, iterate over inverseMap to print the results. Note that if a count does exist twice in originalMap, only one will be printed, which is what you want. But which one gets printed left as an exercise for the reader :-). You might want to be more specific on that.
EDIT ADDED: If you do want to print out duplicate scores, this is not what you want. The original post I read said to skip if they were the same, but I don't see that after the edits, so I'm not sure if this is what OP wants.
I am trying to figure out how could I get the top 10 values from the HashMap. I was initially trying to use the TreeMap and have it sort by value and then take the first 10 values however it seems that that is not the option, as TreeMap sorts by key.
I want to still be able to know which keys have the highest values, the K, V of the map are String, Integer.
Maybe you should implement the Comparable Interface to your value objects stored in the hashmap.
Then you can create a array list of all values:
List<YourValueType> l = new ArrayList<YourValueType>(hashmap.values());
Collection.sort(l);
l = l.subList(0,10);
Regards
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Testing {
public static void main(String[] args) {
HashMap<String,Double> map = new HashMap<String,Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String,Double> sorted_map = new TreeMap<String,Double>(bvc);
map.put("A",99.5);
map.put("B",67.4);
map.put("C",67.4);
map.put("D",67.3);
System.out.println("unsorted map: "+map);
sorted_map.putAll(map);
System.out.println("results: "+sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
I am afraid you'll have to iterate over the entire map. Heap is a commonly-used data structure for finding top K elements, as explained in this book.
If you are trying to get the 10 highest values of the map (assuming the values are numeric or at least implementing Comparable) then try this:
List list = new ArrayList(hashMap.values());
Collections.sort(list);
for(int i=0; i<10; i++) {
// Deal with your value
}
Let's assume you have a Map, but this example can work for any type of
Map<String, String> m = yourMethodToGetYourMap();
List<String> c = new ArrayList<String>(m.values());
Collections.sort(c);
for(int i=0 ; i< 10; ++i) {
System.out.println(i + " rank is " + c.get(i));
}
I base my answer in this one from sk2212
First you need to implement a descending comparator:
class EntryComparator implements Comparator<Entry<String,Integer>> {
/**
* Implements descending order.
*/
#Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (o1.getValue() < o2.getValue()) {
return 1;
} else if (o1.getValue() > o2.getValue()) {
return -1;
}
return 0;
}
}
Then you can use it in a method such as this one for the attribute "hashmap":
public List<Entry<String,Integer>> getTopKeysWithOccurences(int top) {
List<Entry<String,Integer>> results = new ArrayList<>(hashmap.entrySet());
Collections.sort(results, new EntryComparator());
return results.subList(0, top);
}
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
// Initialize map
System.out.println(getTopKeysWithOccurences(map, 10));
}
public static List<Entry<String,Integer>> getTopKeysWithOccurences(Map mp, int top) {
List<Entry<String,Double>> results = new ArrayList<>(mp.entrySet());
Collections.sort(results, (e1,e2) -> e2.getValue() - e1.getValue());
//Ascending order - e1.getValue() - e2.getValue()
//Descending order - e2.getValue() - e1.getValue()
return results.subList(0, top);
}
Example:
String wholeString =
"Typical models for star formation assume that every type of galaxy produces stars"
I'd like to store the splitted string and its following (+1) String in a treemap:
with windowSize = 4 (predefined):
Typi,ypic -> put into TreeMap
ypic,pica -> put into TreeMap
for windowSize = 2 it would look like this:
Ty,yp -> TreeMap
and so on.
My code so far:
Map<String, String> generateMap = new TreeMap<String, String>();
for (int i = 0; i < wholeString.length(); i++) {
generateMap
.put((wholeString.substring((i),
Math.min((i + windowSize), wholeString.length()))),
(wholeString.substring(
(i + 1),
(Math.min((i + windowSize),
wholeString.length())))));
}
If I sysprint it, I gets this:
{ Augen=Augen, Außen=Außen, Innen=Innen, Jauch=Jauch,and so on
My take:
final String wholeString =
"Typical models for star formation assume that every type of galaxy produces stars";
final int windowSize = 4;
final Map<String, String> generateMap = new LinkedHashMap<String, String>();
final int limit = wholeString.length() - windowSize;
for (int i = 0; i < limit;) generateMap.put(
wholeString.substring(i, i + windowSize),
wholeString.substring(++i, i + windowSize));
for (Map.Entry<String, String> e : generateMap.entrySet())
System.out.println(e.getKey() + " -> " + e.getValue());
Here you go (I changed the TreeMap by a LinkedHashMap for debug purposes, you can put back the TreeMap if your prefer):
import java.util.LinkedHashMap;
import java.util.Map;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
Map<String, String> generateMap = new LinkedHashMap<String, String>();
String wholeString = "Typical models for star formation assume that every type of galaxy produces stars";
int windowSize = 4;
for (int i = 0; i < wholeString.length(); i++) {
int start = i;
int end = Math.min(i + windowSize, wholeString.length());
int start1 = Math.min(i + 1, wholeString.length() - 1);
int end1 = Math.min(i + 1 + windowSize, wholeString.length());
generateMap.put(wholeString.substring(start, end), wholeString.substring(start1, end1));
}
System.err.println(generateMap);
}
}
If you like recursion, you may try this:
import java.util.LinkedHashMap;
import java.util.Map;
public class Subs {
/**
* #param args
*/
public static void func(Map<String,String> map, String input, int windowSize) {
if (input.length() <= windowSize) {
map.put(input, input);
return;
} else {
map.put(input.substring(0, windowSize), input.substring(1, windowSize + 1));
func(map, input.substring(1), windowSize);
}
}
public static void main(String[] args) {
String wholeString = "Typical models for star formation assume that every type of galaxy produces stars";
Map<String,String> ourMap = new LinkedHashMap<String, String>();
int windowSize = 4;
func(ourMap, wholeString, windowSize);
System.out.print(ourMap);
}
}
Please note that I'm using 'LinkedHashMap', so output will be in order you put values into it. If you need to put into a TreeMap, simply replace LinkedHashMap with TreeMap and add import statement. But result will be sorted in natural order, not the order you put your values in.