[英]Java Custom Sort Order Round Robin-ish sorting
我是Java開發人員,但我正在為我需要做的特定類型的排序找到一個好的算法。
基本上,我將從查詢中返回一些數據(最多幾千行)。 我只關心基於單個列的排序。 具有諷刺意味的是,該列可能已經被排序,但不是我需要它的方式。
就是這樣:
我得到了一個用戶ID列表,我需要對它進行排序,使其在整個列表中運行並重新開始。 一個簡單的例子比解釋更容易:
假設數據是這樣的:
AAAABBCDD
我的目的的有效排序順序是這樣的:
ABCDABDAA
基本上,我需要每個用戶在回到它們之前“轉彎”。 可能會有不均勻的用戶數量,因此任何額外的用戶都可以在最后堆疊。
同樣,我在Java中這樣做,但此時並未鎖定到特定的數據結構等。
[附加信息:如果它有幫助,特別是我正在做的是為負載測試生成數據並希望最小化同一用戶多次登錄到應用程序,所以我希望我的測試在返回之前循環遍歷所有可用的應用程序用戶到列表的開頭。 但是,數據是真實數據,我不能保證每個用戶都有相同數量的活動。
謝謝! 湯姆
這是我的解決方案。
它不需要輸入數據已經排序。
基本上它會創建一個帶有ID的Map
和它們出現的次數,然后循環遍歷此映射以在每次使用不同的id時選擇,直到映射為空。
public static void main(String[] args) {
List<String> ids = Arrays.asList("A", "A", "A", "A", "B", "B", "C", "D", "D");
List<String> idsOrdered = order(ids);
idsOrdered.forEach(System.out::println);
}
private static List<String> order(List<String> ids) {
// create a map with ids and their occurrences
Map<String, Long> occurs = ids.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<String> idsOrdered = new ArrayList<>();
while (!occurs.isEmpty()) {
// add all the ids in the map to the list
occurs.forEach((k, v) -> idsOrdered.add(k));
// decrement the counter of all ids
occurs.replaceAll((k, v) -> v - 1);
// remove the ids with the counter at 0
occurs.entrySet().removeIf(e -> e.getValue() == 0);
}
return idsOrdered;
}
這是相同的解決方案,但“老學校”(沒有功能編程):
private static List<String> order(List<String> ids) {
// create a map with ids and their occurrences
Map<String, Integer> occurs = new HashMap<>();
for (String id : ids) {
Integer occur = occurs.get(id);
if (occur != null) {
occurs.put(id, occur + 1);
}
else {
occurs.put(id, 1);
}
}
List<String> idsOrdered = new ArrayList<>();
while (!occurs.isEmpty()) {
// loop through the map
Iterator<Entry<String, Integer>> it = occurs.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> pair = it.next();
// add the key to the list
String key = pair.getKey();
idsOrdered.add(key);
// update the occurrences, if 0 then remove the id from the map
int newOccur = pair.getValue() - 1;
if (newOccur == 0) {
it.remove();
}
else {
pair.setValue(newOccur);
}
}
}
return idsOrdered;
}
通過您想要的任何分組功能將值分組為LinkedList類型結構。
通過輪詢每個組將它們添加到最終結果集合中。
例)
鑒於:
public class MyObject {
private String name;
public MyObject(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
數據集:
List<MyObject> objects = new ArrayList<>();
objects.addAll( Arrays.asList(
new MyObject("A"),
new MyObject("C"),
new MyObject("A"),
new MyObject("B"),
new MyObject("B"),
new MyObject("B"),
new MyObject("A"),
new MyObject("A"),
new MyObject("C"),
new MyObject("C"),
new MyObject("A"),
new MyObject("C")
));
功能:
public static Queue<MyObject> robin(List<MyObject> objects) {
if(objects.size() == 0) return new LinkedList<>();
// Group into queues using the getName method
Map<String, Queue<MyObject>> map = objects.stream()
.collect(Collectors.groupingBy(MyObject::getName, Collectors.toCollection(LinkedList::new)));
boolean remaining = true;
Deque<MyObject> roundRobin = new LinkedList<MyObject>();
Set<String> keySet = map.keySet();
// Round robin structure to collect them into a single collection
while(remaining) {
remaining = false;
for(String key : keySet) {
MyObject obj = map.get(key).poll();
if(obj == null) continue;
roundRobin.add(obj);
remaining = true;
}
}
// Return result
return roundRobin;
}
訂購結果:
ABCABCABCACA
基於
基本上,我需要每個用戶在回到它們之前“轉彎”。 可能會有不均勻的用戶數量,因此任何額外的用戶都可以在最后堆疊。
我不確定你的問題是否正在排序。 在我看來,你想要計算(假設用戶沒有特定的正確順序)。
如何將所有用戶放在LinkedHashMap<User, Integer>
,從查詢中插入所有用戶,如果用戶已經在地圖中,則增加計數器。 然后你將遍歷地圖(用戶現在總是以相同的順序),並在每個條目中調用你的工作,減少計數器,如果計數器達到零,你刪除條目。 (一旦地圖為空終止)
如果使用手動迭代器執行此操作,則計數器更新和條目刪除將很快。
當然,由於為每個用戶創建了新對象,所以會產生開銷,所以這一切都取決於每個用戶的平均計數器值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.