2016-04-01 4 views
-3

サイズnのリストが与えられた場合、各リストに含まれるすべての可能な要素の組み合わせを返すプログラムを作成します。リストのリストの外積を返します。

例:

  • リストA = "X、Z"
  • リストB = "B、C"
  • リストC = "O、P"

出力:

  • XAO
  • XA P
  • X B、X、B pを
  • oを.....
  • Z C P

順序は重要ではありませんが、難しい部分がある:あなたが再帰を使用することはできません。 私の解決策:

void combos(const char *string) 
{ 
    int i, j, k; 
    int len = strlen(string); 

    for (i = 0; i < len - 2; i++) 
    { 
     for (j = i + 1; j < len - 1; j++) 
     { 
      for (k = j + 1; k < len; k++) 
       printf("%c%c%c\n", string[i], string[j], string[k]); 
     } 
    } 
} 

あなたが見ることができるように、私は手を前にリストの数を知っていれば、それだけで動作します。再帰がそれを解決する唯一の方法だと私は興味があります。

+0

タグが付けられたすべての言語のソリューションを明示的に求めているのですか、それともあなただけに興味がありますか? – AndyG

+8

ねえ、あなたは 'php'タグを忘れています:) –

+0

言語を選んでください。 –

答えて

2

基数3の数字は次のようになります。

000 
001 
002 
010 
011 
... 
222 

ここで、各数字は各ネストされたリストのインデックスです。ネストしたリストと同じくらい多くの桁数、つまりアウターリストのサイズがあります。

各桁の「ベース」は異なる場合があり、対応するネストされたリストのサイズです。ネストされたリストが大きい場合、「数字」は非常に大きな数値になります。

したがって、数字のリスト(インデックス値)を作成してから、0に初期化します。それらのインデックスにある要素の値を出力します。最後のインデックス値をインクリメントし、必要に応じてロールオーバーします。通常の数と同じように、最初のインデックス値がロールオーバーすると停止します。

ここでは、配列の配列を使用するJava実装、つまりString[][]があります。必要に応じてList<List<String>>またはList<String[]>に簡単に変更できます。あなたの代わりに配列のリストを使用している場合は

@SafeVarargs 
public static void printCombos(String[] ... lists) { 
    if (lists.length == 0) 
     throw new IllegalArgumentException("No lists given"); 
    for (String[] list : lists) 
     if (list.length == 0) 
      throw new IllegalArgumentException("List is empty"); 

    int[] idx = new int[lists.length]; 
    for (;;) { 
     // Print combo 
     for (int i = 0; i < lists.length; i++) { 
      if (i != 0) 
       System.out.print(' '); 
      System.out.print(lists[i][idx[i]]); 
     } 
     System.out.println(); 

     // Advance to next combination 
     for (int i = lists.length - 1; ++idx[i] == lists[i].length;) { 
      idx[i] = 0; 
      if (--i < 0) 
       return; // We're done 
     } 
    } 
} 

public static void main(String[] args) { 
    String[][] data = { { "x", "z" }, { "a", "b", "c" }, { "o", "p" } }; 
    printCombos(data); 
} 

OUTPUTは

x a o 
x a p 
x b o 
x b p 
x c o 
x c p 
z a o 
z a p 
z b o 
z b p 
z c o 
z c p 

、その後、コードは常にパフォーマンスのために良くないかもしれませんget(int)、例えばを使用します。 LinkedListです。

この場合、int[] idxIterator[]に置き換え、各アレイエントリを対応するリストのイテレータで初期化します。問題のリストから新しいIteratorを検索することによって、「数字」を0にリセットする。

この場合、リストである必要はなく、任意の種類のコレクション、具体的にはIterableオブジェクトでもあります。

0

ご存じのように、通常の解決方法は再帰です。しかし、退屈から私は一度JavaメソッドmultiNextを再帰せずにこれを書いた。 multiNextは、配列を使用して、ネストされたループの同等のシステム内のインデックスのロードを追跡します。

public static boolean multiNext(int[] current, int[] slotLengths) { 
    for (int r = current.length - 1; r >= 0; r--) { 
     if (current[r] < slotLengths[r] - 1) { 
      current[r]++; 
      return true; 
     } else { 
      current[r] = 0; 
     } 
    } 
    return false; 
} 

public static void cross(List<List<String>> lists) { 
    int size = lists.size(); 
    int[] current = new int[size]; 
    int[] slotLengths = new int[size]; 
    for (int i = 0; i < size; i++) 
     slotLengths[i] = lists.get(i).size(); 
    do { 
     List<String> temp = new ArrayList<>(); 
     for (int i = 0; i < size; i++) 
      temp.add(lists.get(i).get(current[i])); 
     System.out.println(temp); 
    } while (multiNext(current, slotLengths)); 
} 

public static void main(String[] args) { 
    cross(Arrays.asList(Arrays.asList("x", "z"), Arrays.asList("a", "b", "c"), Arrays.asList("o", "p"))); 
} 
2

再帰は必要ありません。あなたがする必要があるのは、一連の中間的な解決策を構築することだけです。 Pythonの非再帰的な解法は次のとおりです。

# This does NOT use recursion! 
def all_comb(list_of_lists): 
    # We start with a list of just the empty set. 
    answer = [[]] 
    for list in list_of_lists: 
     # new_answer will be the list of combinations including this one. 
     new_answer = [] 
     # Build up the new answer. 
     for thing in list: 
      for prev_list in answer: 
       new_answer.append(prev_list + [thing]) 
     # Replace the old answer with the new one. 
     answer = new_answer 
    # We now have all combinations of all lists. 
    return answer 

# Demonstration that it works.  
for comb in all_comb([["x", "y"], ["a", "b", "c"], ["o", "p"]]): 
    print(" ".join(comb)) 
1

編集:これは現在、というタグが付けられていますが、pythonは良好な実行可能な疑似擬似コードです。

あなたはすなわちdef f(x): return f(g(x))のように見える形で、末尾再帰形で関数を書くことができれば、それが反復形にそれを回すのは簡単です。残念ながら、通常はテール再帰呼び出しで終わることはないので、いくつかの手口を知る必要があります。

まず第一に、我々はこのように見える機能を持っているとしましょう:

def my_map(func, my_list): 
    if not my_list: 
     return [] 

    return [func(my_list[0])] + change_my_list(my_list[1:]) 

[OK]を、それは再帰が、再帰的な尾ではありませんので、:それは本当に

def my_map(func, my_list): 
    if not my_list: 
     return [] 

    result = [func(my_list[0])] + change_my_list(my_list[1:]) 
    return result 

だ代わりに、私たちが必要機能をわずかに調整して、伝統的にアキュムレータとして知られているものを追加します。

def my_map(func, my_list, acc = []) 
    if not my_list: return acc 
    acc = acc + func(my_list[0]) 
    return my_map(func, my_list[1:], acc + func(my_list[0])) 

真の末尾再帰関数を持っている:私たちは今、def f(x): return g(f(x))からdef f(x): return f(g(x))

を行ってきた、それは非再帰的な形式にその機能をオンにする非常に簡単です:今

def my_map(func, my_list, acc=[]): 
    while True: #added 
     if not my_list: return acc 
     #return my_map(func, my_list[1:], acc + func(my_list[0])) #deleted 
     func, my_list, acc = func, my_list[1:], acc + func(my_list[0]) #added 

、アップ私たちはきちんと少し:

def my_map(func, my_list): 
    acc = [] 
    while my_list: 
     acc.append(func(my_list[0]) 
     my_list = my_list[1:] 

    return acc 

注意あなたがさらにforループやリストの内包表記を使用して、それをクリーンアップすることができますが、それは読者の練習として残しています。

これは病理学的な例です。pythonにはmapという組み込み関数がありますが、プロセスは同じです:末尾の再帰的フォームに変換し、再帰呼び出しを引数の再割り当てで置き換えます。アップ。だから、

、あなたが持っている場合:、再び

def make_products(list_of_lists): 
    acc=[] 
    while list_of_lists: 
     first_list = list_of_lists[0] 
     rest = list_of_lists[1:] 

     acc = product_of(acc, first_list) 
     list_of_lists = rest 

    return acc 

この缶:

def make_products(list_of_lists): 
    if not list_of_lists: return [] 
    first_list = list_of_lists[0] 
    rest = list_of_lists[1:] 
    return product_of(first_list, make_products(rest)) 

をあなたに簡素化すること、そして、末尾再帰形式に

def make_products(list_of_lists, acc=[]): 
    if not list_of_lists: return acc 
    first_list = list_of_lists[0] 
    rest = list_of_lists[1:] 
    acc = product_of(acc, first_list) 
    return make_products(rest, acc) 

を変換することができますさらに清掃して、forループに入れます:

def make_products(list_of_lists): 
    acc=[] 

    for lst in list_of_lists: 
     acc = product_of(acc, lst) 

    return acc 

あなたは組み込み関数で見てきた場合、あなたはこのことを気づくかもしれませんが、多少よく知っている:

def reduce(function, iterable, initializer): 
    acc = initializer 
    for x in iterable: 
     acc = function(acc, x) 
    return acc 

ので、最終的な形は

def make_products(list_of_lists): 
    return reduce(product_of, list_of_lists, []) # the last argument is actually optional here 
のようなものがある:それは、本質的に reduce機能です

それでは、product_of関数の記述について心配する必要があります。

関連する問題