0

(実際のクラスのように) 2 つの Java リストがあり、それぞれに番号付きリストとレベルの要素があり、String オブジェクトとして表現されます。以下の各行は、リスト内の個別の文字列です。たとえば、最初のリストは次のようになります。

==level 1==
1.1 2


==level 2==
1.R4 0
2.0 2


==level 3==
3.R3 1
4.R5 1

2番目は次のようになります。

==level 3==
1.null
2.null

リストはそれぞれ任意の長さにすることができ、数値の後の値はここでは関係ありません。目標は、一致するレベルのリストをマージすることです。たとえば、上記の 2 つのリストをマージすると、次のようになります。

==level 1==
1.1 2


==level 2==
1.R4 0
2.0 2


==level 3==
1.null
2.null
3.R3 1
4.R5 1

2 つのリストの一致するレベルの数値が同じになることはないため、確認する必要はありません。また、数字は常に連続していると思います。これは私がこれまでに持っているものですが、すべてのケースをカバーしているわけではありません。特に、マージがレベルの最初または最後でのみ行われる場合です。見ていてもかなり不愉快です。tempLines と lines は 2 つのリストです。

for(int x=0; x < lines.size();x++){
            for(int y=0; y < tempLines.size();y++){
                if(tempLines.get(y).equals(lines.get(x)) && !(tempLines.get(y).equals("\n"))&& !(lines.get(x).equals("\n"))){
                    int a=y+1;
                    int b=x+1;
                    while(!(tempLines.get(a).equals("\n"))){
                        while(!(lines.get(b).equals("\n"))){
                            if(Integer.valueOf(tempLines.get(a).charAt(0))==(Integer.valueOf(tempLines.get(a).charAt(0))-1))
                                lines.add(b,tempLines.get(a));
                        }
                    }
                }
            }
        }

誰か助けてくれませんか?

4

4 に答える 4

2

両方の入力リストが昇順でソートされている場合、2 つのソートされたリスト/配列をマージする標準的な方法を使用できます。要点は、アルゴリズムにネストされたループを含める必要はなく、両方のリストを交互に調べて、常に結果に下位の要素を追加し、そのリストを進めることです。これは、数値とレベルの違いに関するスケッチです。

int ix_a = 0;
int ix_b = 0;
List<String> result = new ArrayList<String>();
while (ix_a < A.size() || ix_b < B.size()) {

    // No more elements in A => append everything from B to result
    if (ix_a == A.size()) {
        result.add(B.get(ix_b));
        ix_b++;
        continue;
    }

    // No more elements in B => append everything from A to result
    if (ix_b == B.size()) {
        result.add(A.get(ix_a));
        ix_a++;
        continue;
    } 

    // Always append the lower element and advance in that list. 
    // If both lists contain the same element, append this once and advance in both lists
    // Distinguish between levels and numbers here, levels take higher precedence.
    String a = A.get(ix_a);
    String b = B.get(ix_b);
    if (isLevel(a) && isLevel(b)) {
        if (isLowerLevel(a, b)) {
            result.add(a);
            ix_a++;
        } else if (isLowerLevel(b, a)) {
            result.add(b);
            ix_b++;
        } else {
            result.add(a);
            ix_a++;
            ix_b++;
        }
    } else if (isLevel(a)) {
        result.add(b);
        ix_b++;
    } else if (isLevel(b)) {
        result.add(a);
        ix_a++;
    } else {
        if (isLowerNumber(a, b)) {
            result.add(a);
            ix_a++;
        } else if (isLowerNumber(b, a)) {
            result.add(b);
            ix_b++;
        } else {
            result.add(a);
            ix_a++;
            ix_b++;
        }
    }
}

これは、不必要に重複するチェックisLevel(...)などを除外することでさらに最適化できます。また、空行の処理も追加する必要があります。

于 2013-03-21T20:28:24.033 に答える
1

基本的に、各レベルをキーとして、行のリストを値として配置する Map を使用する必要があります。マージするリストの処理が終了したら、キー セットを取得して降順に並べ替え、レベルを並べ替えます。次に、ソートされたキー/レベルを使用してマップ値の反復を開始できます。レベルを dest リストに追加し、実際のレベルのリストをソートし、そのすべての要素を dest にも追加します。

これが私が思いついたものです:

public class MergeLists {

    private final static String[] list1 = {
        "==level 1==\r\n", 
        "1.1 2\r\n", 
        "\r\n", 
        "\r\n", 
        "==level 2==\r\n", 
        "1.R4 0\r\n", 
        "2.0 2\r\n", 
        "\r\n", 
        "\r\n", 
        "==level 3==\r\n", 
        "3.R3 1\r\n", 
        "4.R5 1"
    };

    private final static String[] list2 = {
        "==level 3==\r\n", 
        "1.null\r\n", 
        "2.null"
    };

    @Test
    public void mergLists() {
        List<List<String>> listList = new ArrayList<>();
        listList.add(Arrays.asList(list1));
        listList.add(Arrays.asList(list2));
        List<String> mergedList = mergLists(listList);
        for(String s : mergedList) {
            System.out.println(s);
        }
    }

    public List<String> mergLists(List<List<String>> listList) {
        List<String> mergedList = new ArrayList<>();
        Map<String, List<String>> levelMap = new HashMap<String, List<String>>();
        for(int j = 0; j < listList.size(); j++) {
            List<String> list = listList.get(j);
            String actLevel = null;
            for(int i = 0; i < list.size(); i++) {
                String line = list.get(i).trim();
                if(isLevel(line)) {
                    actLevel = line;
                } else {
                    if(actLevel != null) {
                        List<String> levelList = levelMap.get(actLevel);
                        if(levelList == null) {
                            levelList = new ArrayList<>();
                            levelMap.put(actLevel, levelList);
                        }
                        levelList.add(line);
                    } else {
                        System.out.println("line " + (i+1) + " in list " + (j+1) + " does not belong to a level.");
                    }
                }
            }
        }

        List<String> sortedLevelList = new ArrayList<>(levelMap.keySet());
        Collections.sort(sortedLevelList, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return (extractNumberFromLevel(o1) - extractNumberFromLevel(o2));
            }

            private int extractNumberFromLevel(String level) {
                // check that this meets the format of your level entry (assuming "==level n==")
                int r = 0;
                int i = level.indexOf("level");
                if(i != -1) {
                    int j = level.lastIndexOf("==");
                    if(j != -1) {
                        String n = level.substring(i + "level".length(), j).trim();
                        try {
                            r = Integer.parseInt(n);
                        } catch(NumberFormatException e) {
                            // ignore and return 0
                        } 
                    }
                }
                return r;
            }
        });

        for(String level : sortedLevelList) {
            List<String> lineList = levelMap.get(level);
            Collections.sort(lineList, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.trim().length() == 0 ? 1 /* this puts the empty string at the end of the list */ 
                            : (extractNumberFromLine(o1) - extractNumberFromLine(o2));
                }

                private int extractNumberFromLine(String o) {
                    // check that this meets the format of your line entry (assuming "n.1 2")
                    int r = 0;
                    int i = o.indexOf('.');
                    if(i != -1) {
                        String n = o.substring(0, i).trim();
                        try {
                            r = Integer.parseInt(n);
                        } catch(NumberFormatException e) {
                            // ignore and return 0
                        }
                    }
                    return r;
                }
            });

            mergedList.add(level);
            mergedList.addAll(lineList);
        }

        return mergedList;
    }

    private boolean isLevel(String line) {
        // check that this meets the format of your level entry (assuming "==level n==")
        return line.contains("level");
    }
}

出力

==level 1==
1.1 2


==level 2==
1.R4 0
2.0 2


==level 3==
1.null
2.null
3.R3 1
4.R5 1
于 2013-03-21T20:24:19.083 に答える
1

私は通常、 で処理することでその問題を回避しMapます。リストなどの別のコレクションを使用することもできますが、マップを使用したコードの方が読みやすいことがわかりました (リストに何百万もの要素が含まれていない限り、おそらくパフォーマンスの問題ではありません)。

この場合、Map<Integer,String>エントリを正しい順序に保つための があります。このようなマップは、キーがレベル番号である別のマップに値として格納されます。TreeMapキーに従ってエントリをソートするため、実装クラスとして使用します。

Map<Integer,Map<Integer,String>> map = new TreeMap<>();
int level=0; //current level
for (String line:templines) {
 if (line.startsWith("==level ")) { 
   level=Integer.valueOf(line.substring(7).replace("==","").trim());
   if (map.get(level)==null) map.put(level,new TreeMap<>());
 } else if (line.length>0) {
   int pos = line.indexOf('.');
   if (pos>0) {
    int n = Integer.valueOf(line.substring(0,pos));
    line=line.substring(pos+1);
    map.get(level).put(n,line); 
   }
 }
}

マップを取得したら、それを繰り返し、値を別のリストに保存します。

List<String> merged = new ArrayList<String>();
for (Map.Entry<Integer,Map<Integer,String>> entry:map.entrySet()) {
  list.add("==level "+entry.getKey()+"==");
  for (String line:entry.getValue().values()) {
   list.add(line);
  }
}
于 2013-03-21T19:36:09.740 に答える
0

コレクションをレベルごとに分割し、ApacheCommonsCollectionsを使用できます。

Collection a = createCollection();
Collection b = createCollection();

Collection c = CollectionUtils.union(a,b);
于 2013-03-21T19:01:50.060 に答える