2015-04-15 69 views
11

我有可变大小的列表,例如拆分列表分为两个子列表中的所有可能的方式

[1, 2, 3, 4] 

,我想每一个可能的方式向此列表分为两个:

([], [1, 2, 3, 4]) 
([1], [2, 3, 4]) 
([2], [1, 3, 4]) 
([3], [1, 2, 4]) 
([4], [1, 2, 3]) 
([1, 2], [3, 4]) 
([1, 3], [2, 4]) 
([1, 4], [2, 3]) 
([2, 3], [1, 4]) 
([2, 4], [1, 3]) 
([3, 4], [1, 2]) 
([1, 2, 3], [4]) 
([1, 2, 4], [3]) 
([1, 3, 4], [2]) 
([2, 3, 4], [1]) 
([1, 2, 3, 4], []) 

我很确定这不是一个未知的问题,有可能是一个算法,但我找不到一个。此外,这不应该使用任何外部库,而是使用大多数语言中的简单语言功能(循环,条件,方法/函数,变量等)。

我用Python编写的一个hackish的解决方案:

def get_all(objects): 
    for i in range(1, len(objects)): 
     for a in combinations(objects, i): 
      for b in combinations([obj for obj in objects if obj not in up], len(objects) - i): 
       yield State(up, down) 
    if objects: 
     yield State([], objects) 
     yield State(objects, []) 

但是,它使用的库功能,但非常好看一般。

+3

我们这里不写代码。我们帮助人们获得解决方案。你需要向我们展示一些努力。 –

+0

我在Python中编写了一个黑客解决方案。 – LeoTietz

+0

你应该发布它。 – Brionius

回答

4
l = [1, 2, 3, 4] 
flags = [False] * len(l) 
while True: 
    a = [l[i] for i, flag in enumerate(flags) if flag] 
    b = [l[i] for i, flag in enumerate(flags) if not flag] 
    print a, b 
    for i in xrange(len(l)): 
     flags[i] = not flags[i] 
     if flags[i]: 
      break 
    else: 
     break 

结果:

[] [1, 2, 3, 4] 
[1] [2, 3, 4] 
[2] [1, 3, 4] 
[1, 2] [3, 4] 
[3] [1, 2, 4] 
[1, 3] [2, 4] 
[2, 3] [1, 4] 
[1, 2, 3] [4] 
[4] [1, 2, 3] 
[1, 4] [2, 3] 
[2, 4] [1, 3] 
[1, 2, 4] [3] 
[3, 4] [1, 2] 
[1, 3, 4] [2] 
[2, 3, 4] [1] 
[1, 2, 3, 4] [] 

它可以很容易地适应到Java:

public static void main(String[] args) { 
    int[] l = new int[] { 1, 2, 3, 4 }; 
    boolean[] flags = new boolean[l.length]; 
    for (int i = 0; i != l.length;) { 
     ArrayList<Integer> a = new ArrayList<>(), b = new ArrayList<>(); 
     for (int j = 0; j < l.length; j++) 
      if (flags[j]) a.add(l[j]); else b.add(l[j]); 
     System.out.println("" + a + ", " + b); 
     for (i = 0; i < l.length && !(flags[i] = !flags[i]); i++); 
    } 
} 
+0

这实际上可能是一种可能性,为大多数主要语言实现/存在。我不确定使用zip,但是看看python文档,它看起来像在其他语言中开发的(相对)简单的事情。 – LeoTietz

+0

我更新了我的答案 – JuniorCompressor

1

去在所有不同尺寸的组合,并从原来的列表“中减去”他们似乎直觉方法IMO:

from itertools import combinations 

s = [1, 2, 3, 4] 
for combs in (combinations(s, r) for r in range(len(s)+1)) : 
    for comb in combs: 
     diff = list(set(s[:]) - set(comb)) 
     print diff, list(comb) 

输出

[1, 2, 3, 4] [] 
[2, 3, 4] [1] 
[1, 3, 4] [2] 
[1, 2, 4] [3] 
[1, 2, 3] [4] 
[3, 4] [1, 2] 
[2, 4] [1, 3] 
[2, 3] [1, 4] 
[1, 4] [2, 3] 
[1, 3] [2, 4] 
[1, 2] [3, 4] 
[4] [1, 2, 3] 
[3] [1, 2, 4] 
[2] [1, 3, 4] 
[1] [2, 3, 4] 
[] [1, 2, 3, 4] 

同样的方法可以使用Java(仅适用于它的更详细的...)应用:

private static List<Integer> initial; 

public static void main(String[] args) throws IOException { 
    initial = Arrays.asList(1, 2, 3); 
    combinations(initial); 
} 

static void combinations(List<Integer> src) { 
    combinations(new LinkedList<>(), src); 
} 

private static void combinations(LinkedList<Integer> prefix, List<Integer> src) {   
    if (src.size() > 0) { 
     prefix = new LinkedList<>(prefix); //create a copy to not modify the orig 
     src = new LinkedList<>(src); //copy 
     Integer curr = src.remove(0); 
     print(prefix, curr); // <-- this is the only thing that shouldn't appear in a "normal" combinations method, and which makes it print the list-pairs 
     combinations(prefix, src); // recurse without curr 
     prefix.add(curr); 
     combinations(prefix, src); // recurse with curr 
    } 
} 

// print the prefix+curr, as one list, and initial-(prefix+curr) as a second list 
private static void print(LinkedList<Integer> prefix, Integer curr) { 
    prefix = new LinkedList<>(prefix); //copy 
    prefix.add(curr); 
    System.out.println(Arrays.toString(prefix.toArray()) + 
        " " + Arrays.toString(subtract(initial, prefix).toArray())); 
} 

private static List<Integer> subtract(List<Integer> initial, LinkedList<Integer> prefix) { 
    initial = new LinkedList<>(initial); //copy 
    initial.removeAll(prefix); 
    return initial; 
} 

输出

[1] [2, 3] 
[2] [1, 3] 
[3] [1, 2] 
[2, 3] [1] 
[1, 2] [3] 
[1, 3] [2] 
[1, 2, 3] [] 
+0

如果我有令人惊叹的Python库,但是在Java和C这样的语言中,这很难写。 – LeoTietz

+0

@LeoTietz你想要一个不需要库的答案,请查看答案的Java部分。 – alfasin

2

更低廉使用按位算术计算应易于转换为Java的子集的解决方案:

def sublists(xs): 
    l = len(xs) 
    for i in range(1 << l): 
     incl, excl = [], [] 
     for j in range(l): 
      if i & (1 << j): 
       incl.append(xs[j]) 
      else: 
       excl.append(xs[j]) 
     yield (incl, excl) 
+0

这是一些非常聪明的东西,使用2和二进制的幂。 +(2^0)! – Shashank

2

虽然在Python中,它很容易与它丰富的图书馆获得的结果,在Java中,你可以写一个递归解决方案。下面将打印您阵列的所有可能的组合:

public static void main(String[] args) { 
    List<Integer> num = Arrays.asList(1, 2, 3, 4); 
    List<List<Integer>> sublists = new ArrayList<List<Integer>>(); 
    for (int i = 0; i <= num.size(); i++) { 
     permutation(num, sublists, i, new ArrayList<Integer>(), 0); 
    } 

    for (List<Integer> subList : sublists) { 
     List<Integer> numCopy = new ArrayList<Integer>(num); 
     numCopy.removeAll(subList); 
     System.out.println("(" + subList + ", " + numCopy + ")"); 
    } 
} 

public static void permutation(List<Integer> nums, List<List<Integer>> subLists, int sublistSize, List<Integer> currentSubList, 
     int startIndex) { 
    if (sublistSize == 0) { 
     subLists.add(currentSubList); 
    } else { 
     sublistSize--; 
     for (int i = startIndex; i < nums.size(); i++) { 
     List<Integer> newSubList = new ArrayList<Integer>(currentSubList); 
     newSubList.add(nums.get(i)); 
     permutation(nums, subLists, sublistSize, newSubList, i + 1); 
     } 
    } 
} 

sublists发现携带到现在的所有组合。最后一个参数是当前子列表下一个元素的startIndex。这是为了避免重复。