Java-如何合并基于第三个列表的两个列表?

我尝试解决问题已经有2天了,我的算法似乎太复杂了。 我需要产生1个数据列表,这些数据合并2个有序列表(在“列表A”和“列表B”下命名) 此合并必须基于引用有序列表,以标识每个元素将放置在何处。 如果列表A和列表B的排名值相同,那么我只需要保留其中一个

Ex:

  

参考列表:1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
  清单A:2 | 4 | 6
  清单B:1 | 4

     

预期结果:1 | 2 | 4 | 6

代码

private static List<String> mergeListsUsingRef(final List<String> listRef,final List<String> listA,final List<String> listB) {
    final List<String> res = new ArrayList<>();

    final Iterator<String> listRefIterator = listRef.iterator();
    final Iterator<String> listAIterator = listA.iterator();
    final Iterator<String> listBIterator = listB.iterator();

    String a = listAIterator.hasnext() ? listAIterator.next() : null;
    String b = listBIterator.hasnext() ? listBIterator.next() : null;
    while (listRefIterator.hasnext() && (a != null || b != null)) {
        final String ref = listRefIterator.next();

        if (a != null && ref.equals(a)) {
            res.add(a);

            if (b != null && ref.equals(b)) {
                b = listBIterator.hasnext() ? listBIterator.next() : null;
            }
            a = listAIterator.hasnext() ? listAIterator.next() : null;
        } else if (b != null && ref.equals(b)) {
            res.add(b);

            b = listBIterator.hasnext() ? listBIterator.next() : null;
        }
    }
    return res;
}

现在我必须使最初的问题复杂化。主要的困难来自可能在每个列表中多次具有相同的值。 这意味着找出允许重复值使用的位置。

让我们想象一些示例来说明这一点(其中4个出现在参考列表中两次)

  

参考列表:1 | 2 | 3 | 4 | 5 | 6 | 4 | 7 | 8
  清单A:2 | 3 | 5 | 4 | 7
  清单B: 4 | 7 | 8

     

预期结果:2 | 3 | 5 | 4 | 7 | 8

     
    

说明:
    在列表A中:对于参考列表,4在5到7之间,因此4只能放在第二位
    在列表B中:关于参考列表,我无法确定4的位置(第一或第二位)
    因此,列表A确定4在第二排的位置

  

  

参考列表:1 | 2 | 3 | 4 | 5 | 6 | 4 | 7 | 8
  清单A:2 | 3 | 4 | 5 | 7
  清单B: 4 | 7 | 8

     

预期结果:2 | 3 | 4 | 5 | 7 | 8

     
    

说明:
    在列表A中:对于参考列表,4在3到5之间,因此4只能放在第一位
    在列表B中:关于参考列表,我无法确定4的位置(第一或第二位)
    因此,列表A确定了4在第一排的位置

  

  

参考列表:1 | 2 | 3 | 4 | 5 | 6 | 4 | 7 | 8
  清单A:2 | 3 | 4 | 5 | 7
  清单B:6 | 4 | 7 | 8

     

预期结果:2 | 3 | 4 | 5 | 6 | 4 | 7 | 8

     
    

说明:
    在列表A中:对于参考列表,4在3到5之间,因此4只能放在第一位
    在列表B中:关于参考列表,4在6到7之间,因此4只能放在第二位
    因此,必须将4位放在第一和第二位

  

  

参考列表:1 | 2 | 3 | 4 | 5 | 6 | 4 | 7 | 8
  清单A:2 | 3 | 4 | 5 | 7
  清单B:6 | 7 | 8

     

预期结果:2 | 3 | 4 | 5 | 6 | 7 | 8

     
    

说明:
    在列表A中:对于参考列表,4在3到5之间,因此4只能放在第一位
    在列表B中:0出现4     因此,列表A确定了4在第一排的位置

  

我以前的代码无法处理这些困难的情况。 有谁知道如何帮助我推进其实施? :)

编辑: 验证Java的主要实现:D

public static void main(String[] args) {
System.out.println("EX 1 : ");
        List<String> refList = Arrays.asList("1","2","3","4","5","6","7","8");
        List<String> listA = Arrays.asList("2","7");
        List<String> listB = Arrays.asList("4","8");
        List<String> mergeListsUsingRef = mergeListsUsingRef(refList,listA,listB);
        System.out.println("Expected : 2 | 3 | 5 | 4 | 7 | 8 ");
        System.out.print("actual : ");
        for (String res : mergeListsUsingRef) {
            System.out.print(res + " | ");
        }
        System.out.println("");
        System.out.println("----------------------------------");
        System.out.println("EX 2 : ");
        refList = Arrays.asList("1","8");
        listA = Arrays.asList("2","7");
        listB = Arrays.asList("4","8");
        mergeListsUsingRef = mergeListsUsingRef(refList,listB);
        System.out.println("Expected : 2 | 3 | 4 | 5 | 7 | 8 ");
        System.out.print("actual : ");
        for (String res : mergeListsUsingRef) {
            System.out.print(res + " | ");
        }
        System.out.println("");
        System.out.println("----------------------------------");
        System.out.println("EX 3 : ");
        refList = Arrays.asList("1","7");
        listB = Arrays.asList("6",listB);
        System.out.println("Expected : 2 | 3 | 4 | 5 | 6 | 4 | 7 | 8 ");
        System.out.print("actual : ");
        for (String res : mergeListsUsingRef) {
            System.out.print(res + " | ");
        }
        System.out.println("");
        System.out.println("----------------------------------");
        System.out.println("EX 4 : ");
        refList = Arrays.asList("1",listB);
        System.out.println("Expected : 2 | 3 | 4 | 5 | 6 | 7 | 8 ");
        System.out.print("actual : ");
        for (String res : mergeListsUsingRef) {
            System.out.print(res + " | ");
        }
    }
l595511699 回答:Java-如何合并基于第三个列表的两个列表?

private static List<String> mergeListsUsingRef(List<String> listRefRaw,List<String> listA,List<String> listB) {
    List<String> listRef = uniques(listRefRaw);
    Set<String> common = new HashSet<>();
    common.addAll(listA);
    common.addAll(listB);
    List<String> result = new ArrayList<>(listRef);
    result.retainAll(common);
    return result;
}

如果参考列表与两个列表相比都很大:

    return listRef.stream()
            .filter(common::contains)
            .collect(Collectors.toList());

这将保留参考列表的顺序。这里的主要问题是 listA和listB都没有设置,所以不可能进行快速的包含检查。

private static List<String> uniques(List<String> listRefRaw) {
     Set<String> uniqueValues = new HashSet<>();
     return listRefRaw.stream()
         .filter(s -> !uniqueValues.contains(s))
         .peek(uniqueValues::add)
         .collect(Collectors.toList());
}

很遗憾,Stream.distinct()在无序集合中不稳定, 所以上面应该做。

,

我认为此解决方案将起作用-保留列表的顺序,并为上面显示的所有示例提供正确答案。通过将引用列表保留为索引的hashMap,它可以快速查询任意两个整数(如果一个整数可以在引用之前出现在另一个整数之前)。我在主机上添加了打印输出以进行测试。

 public class ListMergeByRef {

    public Map<Integer,List<Integer>> refMap = new HashMap<Integer,List<Integer>>();
    public ListMergeByRef(List<Integer> reference) {
        int elementIndex = 0;
        for (Integer element:reference) {
            List<Integer> refListPerElement = refMap.get(element);
            if (refListPerElement == null) {
                refListPerElement = new ArrayList<Integer>();
            }
            refListPerElement.add(elementIndex);
            elementIndex++;
            refMap.put(element,refListPerElement);
        }
    }

    public List<Integer> mergeLists (List<Integer> first,List<Integer> second) {
        int firstIndex = 0;
        int secondIndex = 0;
        List<Integer> merged = new ArrayList<Integer>();
        while (firstIndex < first.size() || secondIndex < second.size()) {
            if (firstIndex == first.size()) {
                merged.addAll(second.subList(secondIndex,second.size()));
                return merged;
            } else if (secondIndex == second.size()) {
                merged.addAll(first.subList(firstIndex,first.size()));
                return merged;
            } 

            if (first.get(firstIndex).equals(second.get(secondIndex))){
                merged.add(first.get(firstIndex));
                firstIndex++;
                secondIndex++;
            }
            else if (isElementAllowedBeforeOther(first.get(firstIndex),second.get(secondIndex))) {
                merged.add(first.get(firstIndex));
                firstIndex++;
            } else {
                merged.add(second.get(secondIndex));
                secondIndex++;
            }
        }
        return merged;
    }

    public boolean isElementAllowedBeforeOther(Integer firstElement,Integer secondElement) {
        List<Integer> firstElementIndexes = refMap.get(firstElement);
        List<Integer> secondElementIndexes = refMap.get(secondElement);
        if (firstElementIndexes == null || firstElementIndexes.isEmpty()) return false;
        if (secondElementIndexes == null || secondElementIndexes.isEmpty()) return true;
        if (firstElementIndexes.get(0) < secondElementIndexes.get(secondElementIndexes.size()-1)) return true;
        return false;
    }

    public static void main(String[] args) {
        List<Integer> ref = Arrays.asList(new Integer[] {1,2,3,4,5,6,7,8});
        List<Integer> first = Arrays.asList(new Integer[] {2,7});
        List<Integer> second = Arrays.asList(new Integer[] {4,8});
        ListMergeByRef merger = new ListMergeByRef(ref);
        List<Integer> mergedList = merger.mergeLists(first,second);
        for (Integer element: mergedList) {
            System.out.print(element+" ");
        }
        System.out.println();
    }
,

前两个测试失败,因为您期望的列表缺少第二个4。要合并的列表中存在两个4。

无论如何,我只是遍历了ref并从试图合并的列表中删除了所有匹配项。

public static <E extends Comparable<E>>List<E> merge(List<E> refList,List<E>... lists) {
    List<E> result = new ArrayList<E>();
    Iterator<E> ref = refList.iterator();
    boolean found = false;
    while (ref.hasNext()) {
        E curr = ref.next();
        found = false; // Reset
        for (List<E> list : lists) {
            if (found) continue; // If already found,skip the next list
            for (Iterator<E>it = list.iterator(); !found && it.hasNext();) {
                E term = it.next();
                boolean equal = term.equals(curr);
                if (equal) {
                    result.add(term);
                    list.remove(term);
                    found = true;
                }
            }
        }
    }
    return result;
}

完整示例

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class ListReferenceJoiner {
    public static final boolean DEBUG = true;

    public static void main(String[] args) {
        System.out.printf("Equal? %b%n",test1());
        System.out.println("===================");
        System.out.printf("Equal? %b%n",test2());
        System.out.println("===================");
        System.out.printf("Equal? %b%n",test3());
        System.out.println("===================");
        System.out.printf("Equal? %b%n",test4());
    }

    private static boolean test1() {
        List<Integer> refList = asArrayList(1,8);
        List<Integer> listA = asArrayList(2,7);
        List<Integer> listB = asArrayList(4,8);
        List<Integer> expected = asArrayList(2,8);

        return testRunner(refList,listA,listB,expected); // 2,8
    }

    private static boolean test2() {
        List<Integer> refList = asArrayList(1,8
    }

    private static boolean test3() {
        List<Integer> refList = asArrayList(1,7);
        List<Integer> listB = asArrayList(6,8
    }

    private static boolean test4() {
        List<Integer> refList = asArrayList(1,8
    }

    private static boolean testRunner(List<Integer> ref,List<Integer> listA,List<Integer> listB,List<Integer> expected) {
        if (DEBUG) {
            System.out.printf("Expecting: %s%n",expected);
        }

        List<Integer> actual = merge(ref,listB); // 2,8

        if (DEBUG) {
            System.out.printf("Actual: %s%n",actual);
        }

        return expected.equals(actual);
    }


    @SuppressWarnings("unchecked")
    public static <E extends Comparable<E>>List<E> merge(List<E> refList,List<E>... lists) {
        List<E> result = new ArrayList<E>();
        Iterator<E> ref = refList.iterator();
        boolean found = false;
        while (ref.hasNext()) {
            if (DEBUG) {
                printLists(lists);
            }
            E curr = ref.next();
            found = false; // Reset
            for (List<E> list : lists) {
                if (found) continue; // If already found,skip the next list
                for (Iterator<E>it = list.iterator(); !found && it.hasNext();) {
                    E term = it.next();
                    boolean equal = term.equals(curr);
                    if (equal) {
                        if (DEBUG) {
                            System.out.printf("Found '%s'%n",term);
                        }
                        result.add(term);
                        list.remove(term);
                        found = true;
                    }
                }
            }
            if (DEBUG && !found) {
                System.out.printf("Could not find '%s'%n",curr);
            }
        }
        return result;
    }

    private static <E> void printLists(List<E>... lists) {
        for (ListIterator< List<E>>it = Arrays.asList(lists).listIterator(); it.hasNext();) {
            printList(it.next(),getCharForNumber(it.nextIndex()));
        }
    }

    private static <E> void printList(List<E> list,String label) {
        System.out.printf("%s: ",label);
        for (Iterator< E>it = list.iterator(); it.hasNext();) {
            System.out.print(it.next());
            if (it.hasNext()) {
                System.out.print(" | ");
            }
        }
        System.out.print(System.lineSeparator());
    }

    @SuppressWarnings("unchecked")
    private static <E> List<E> asArrayList(E... values) {
        return new ArrayList<E>(Arrays.asList(values));
    }

    protected static String getCharForNumber(int i) {
        return i > 0 && i < 27 ? String.valueOf((char) (i + 64)) : null;
    }
}

这是莫里斯·佩里(Maurice Perry)的回应版本,但仍然无法保留顺序。

private static <E> List<E> merge(final List<E> listRef,final List<E>... lists) {
    final List<E> res = new ArrayList<E>();
    final List<List<E>> copies = Arrays.stream(lists).map(ArrayList::new).collect(Collectors.toList());
    for (E ref : listRef) {
      boolean found = false;
      for (Iterator<List<E>> it = copies.iterator(); !found && it.hasNext();) {
        if (it.next().remove(ref)) {
              res.add(ref);
              found = true;
          }
      }
      if (found) {
        continue;
      }
    }
    return res;
}

示例输出

Testing: [2,8]
A: 2 | 3 | 5 | 4 | 7
B: 4 | 7 | 8
Could not find '1'
A: 2 | 3 | 5 | 4 | 7
B: 4 | 7 | 8
Found '2'
A: 3 | 5 | 4 | 7
B: 4 | 7 | 8
Found '3'
A: 5 | 4 | 7
B: 4 | 7 | 8
Found '4'
A: 5 | 7
B: 4 | 7 | 8
Found '5'
A: 7
B: 4 | 7 | 8
Could not find '6'
A: 7
B: 4 | 7 | 8
Found '4'
A: 7
B: 7 | 8
Found '7'
A: 
B: 7 | 8
Found '8'
Actual: [2,8]
Equal? false
===================
Testing: [2,8]
A: 2 | 3 | 4 | 5 | 7
B: 4 | 7 | 8
Could not find '1'
A: 2 | 3 | 4 | 5 | 7
B: 4 | 7 | 8
Found '2'
A: 3 | 4 | 5 | 7
B: 4 | 7 | 8
Found '3'
A: 4 | 5 | 7
B: 4 | 7 | 8
Found '4'
A: 5 | 7
B: 4 | 7 | 8
Found '5'
A: 7
B: 4 | 7 | 8
Could not find '6'
A: 7
B: 4 | 7 | 8
Found '4'
A: 7
B: 7 | 8
Found '7'
A: 
B: 7 | 8
Found '8'
Actual: [2,8]
A: 2 | 3 | 4 | 5 | 7
B: 6 | 4 | 7 | 8
Could not find '1'
A: 2 | 3 | 4 | 5 | 7
B: 6 | 4 | 7 | 8
Found '2'
A: 3 | 4 | 5 | 7
B: 6 | 4 | 7 | 8
Found '3'
A: 4 | 5 | 7
B: 6 | 4 | 7 | 8
Found '4'
A: 5 | 7
B: 6 | 4 | 7 | 8
Found '5'
A: 7
B: 6 | 4 | 7 | 8
Found '6'
A: 7
B: 4 | 7 | 8
Found '4'
A: 7
B: 7 | 8
Found '7'
A: 
B: 7 | 8
Found '8'
Actual: [2,8]
Equal? true
===================
Testing: [2,8]
A: 2 | 3 | 4 | 5 | 7
B: 6 | 7 | 8
Could not find '1'
A: 2 | 3 | 4 | 5 | 7
B: 6 | 7 | 8
Found '2'
A: 3 | 4 | 5 | 7
B: 6 | 7 | 8
Found '3'
A: 4 | 5 | 7
B: 6 | 7 | 8
Found '4'
A: 5 | 7
B: 6 | 7 | 8
Found '5'
A: 7
B: 6 | 7 | 8
Found '6'
A: 7
B: 7 | 8
Could not find '4'
A: 7
B: 7 | 8
Found '7'
A: 
B: 7 | 8
Found '8'
Actual: [2,8]
Equal? true
,

您的代码正常工作!

但是有2个问题:

  • 您的逻辑不需要null检查。

    由于equals(null)required才能返回false,因此可以安全地将if (a != null && ref.equals(a))缩小为if (ref.equals(a))

  • 您对EX 1的期望不正确。

    这些值匹配如下:

    ref:    "1","2","3","4","5","6","7","8"
    ---------------------------------------------------
    A:           "2","7"
    B:                     "4","8"
    ===================================================
    result:      "2","8"
    

    但是你在期待

                 "2","8"
    

    如您所见,您也应该期待第一个 4

本文链接:https://www.f2er.com/3102081.html

大家都在问