簡體   English   中英

按值列表對列表進行排序

[英]Sort a Map of Lists by a List of Values

場景是我有以下地圖:

[
  a:[4,2,6,9,-1],
  b:[2,6],
  c:[1],
  d:[9,9,9,4]
]

以及以下值列表:

[2,4,1]

我希望按排序列表中第一個出現的值對映射鍵進行排序:

result: [a,b,d,c] (because both a&b have a 2, d has a 4, and c has a 1)

目前,我有以下內容,但它位於O(n ^ 3)。 有沒有一種更有效的方法來進行這種處理?

private static List<String> orderByList(Map<String, List<Integer>> numByString, List<String> sortingList) {
    Map<String, List<String>> stringsByTags = new HashMap<String, List<String>>();
    for (String string : numByString.keySet()) {
        for (Integer num : numByString.get(string)) {
            boolean foundTag = false;
            // go through all elements until you find one that is is the sortingList
            // add it to the stringsByTags
            for (String tag : sortingList) {
                if (string.equals(tag)) {
                    if (stringsByTags.containsKey(tag)) {
                        stringsByTags.get(tag).add(string);
                    } else {
                        List<String> newList = new ArrayList<String>();
                        newList.add(string);
                        stringsByTags.put(tag, newList);
                    }
                    foundTag = true;
                    break;
                }
            }
            if (foundTag) {
                break;
            }
        }
    }
    //combine the stringsByTags
    List<String> ordered = new ArrayList<String>();
    for (String tag : sortingList) {
        if (stringsByTags.containsKey(tag)) {
            ordered.addAll(stringsByTags.get(tag));
        }
    }
    return ordered;
}

步驟1 計算地圖中每個條目的分數

    values = [2,4,1];
    Integer score = 0;
    for(int i=0;i < a.size();i++) {
        if(values.binarySearch(a[i])) {
            score ++;
        }
    }

運行時間為* O(a.size() log(values.size)) 計算整個地圖得分的總成本為O(map.size * entry.size * log(values.size))。 以簡單的方式,它將是O(knlog(m))

第二步 ScoreObj數組進行排序。 成本為O(klog(k)) ,其中k表示地圖的大小。

class ScoreObj {
        Integer score;
        String key;
    }

覆蓋的比較功能ScoreObj所以ScoreObj會被它的排序score

O(n ^ 3)好一點

如果我正確理解了您的問題,則您的算法將根據排序列表中找到的第一個值的索引對地圖條目進行排序。 我們將此索引sortingIndex

一種方法是首先創建一個Map<String, Integer> ,其中的鍵保持不變,其值是sortingIndex

Map<String, Integer> sortingMap = new HashMap<>();

numByString.forEach((k, v) -> {
        Set<Integer> values = new HashSet<>(v);
        int sortingIndex = IntStream.range(0, sortingList.size())
            .filter(i -> values.contains(sortingList.get(i)))
            .findFirst()
            .orElse(Integer.MAX_VALUE);
        sortingMap.put(k, sortingIndex);
    });

現在,只需按值排序sortingMap並獲取鍵:

List<String> orderedKeys = sortingMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

我有2種方法,它們的O均應小於您的O。 我的第一種方法的O應該比第二種方法的O小,因為它還會在處理映射條目后刪除它們。 我的測試數據如下所示。 我選擇LinkedHashMap是因為它保持插入順序,這在這種情況下很重要:

Map<String, List<String>> p = new HashMap<String, List<String>>();
p.put("a", Arrays.asList("4", "2", "6", "9", "-1"));
p.put("b", Arrays.asList("2", "6"));
p.put("c", Arrays.asList("1"));
p.put("d", Arrays.asList("9", "9", "9", "4"));
p.put("e", Arrays.asList("8", "7", "6"));
List<String> values = new ArrayList<String>(Arrays.asList("2", "4", "1"));
Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
List<String> sorted = new ArrayList<String>();

現在,我的第一種方法是對條目進行排序后刪除條目:

for (String s : values) {
    for (Iterator<Entry<String, List<String>>> it = p.entrySet().iterator(); it.hasNext();) {
        Map.Entry<String, List<String>> x = it.next();
        if (x.getValue().contains(s)) {
            if (!result.containsKey(x.getKey())) {
                result.put(x.getKey(), x.getValue());
                sorted.add(x.getKey());
                it.remove();
            }
        }
    }
}

第二種方法看起來更容易理解,但效果也很好:

for (String s : values) {
    for (String st : p.keySet()) {
        if (p.get(st).contains(s)) {
            if (!result.containsKey(st)) {
                result.put(st, p.get(st));
                sorted.add(st);
            }
        }
    }
}

如果我同時打印列表和地圖,則兩種情況下的輸出都是這樣的:

[a, b, d, c]
[a, b, d, c]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM