php bellek tükeniyor olmadan eşsiz kombinasyonlar oluşturuyor

5 Cevap php

Ben bir veritabanından öğelerin kombinasyonlarını oluşturmak için bir algoritma yazıyorum. Bu eşsiz permütasyon (yani 145, 156 == 156, 145) olması gerekir. Ben çalıştırıyorum sorun i 145, 156 ve 156, 145 ile sona kalmamak önceki kombinasyonları takip için nasıl.

I kontrol böylece Şu anda ben (id her zaman en yüksek olmak yüzden sıralanır) ... id1_id2 endeksi ile bir dizi ekleyerek ve bir combo oluşturulur, 1'e eşit değerini ayarlama ediyorsam $ tarak [$ index] var ya da yok. O yoksa, oluşturun. Bu kombinasyonlar oluşturulur sonra (orada HER permutation ayıklamak için başka kriterler vardır, ama onlar alakasız), onlar MySQL bir tablo muhafaza edilmektedir.

Ben çalıştırıyorum sorun test öğeleri ile ben kombinasyon sayısı MASİF ve $ kombinasyonları dizi olarak (yaklaşık 85) Ben bellek tükeniyor olmadan fazla 3 ürün (id1_id2_id3) ile kombinasyonları oluşturmak olamaz kullanıyor olmam i PHP bellekte ayrılan am 64M daha alır.

I a) önceki tarak takip veya b) $ tarak dizi rotayı atlama ve sadece MySQL ve MySQL yinelenen kontrolünü ele izin benzersiz bir satır eklemeden yapabilirsiniz bir yolu var mı.

Burada referans için bazı sözde kod:

$items = array(/*85 items*/);
foreach ($items as $item1){
    generate(array($item1));
        foreach($items as $item2){
            generate(array($item1, $item2));
        }
    }
}

function generate($items_arary){
    $temp_array = array();
    foreach ($items_array as $item){
        $temp_array[] = $item['id'];
    }

    sort($temp_array);
    $index = implode("_", $temp_array);

    if (!$combos[$index]){
        $combos[$index] = 1;
        /* some code to generate query to store to db */
    }
}

Sorgu bu gibi bakıyor biter: (veritabanı script başında kesiliyor)

INSERT INTO `combos` (combo_id, more_info) VALUES ('id1_id2', 'Item Name');

Bu soru yazma sürecinde, olası bir çözüm düşündüm: Emin ID3> id2> id1 yapma. Bu $ tarak için ihtiyaç kaldırmak için kalıcı bir çözüm olabilir mi?

5 Cevap

Eğer böyle bir şey yapabileceğini, çünkü ben daha önce veri yapısı hakkında sorulan nedeni:

$sql = "SELECT id FROM test_a";
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
  $item1 = $row['id'];

  $sql2 = "SELECT id FROM test_a";
  $result2 = mysql_query($sql2);
  while ($row2 = mysql_fetch_array($result2)) {
    $item2 = $row2['id'];

    $combo1 = $item1 . "_" . $item2;
    $combo2 = $item2 . "_" . $item1;

    $sql3 = "SELECT * FROM combos WHERE combo_id = '$combo1' OR combo_id = '$combo2'";
    $result3 = mysql_query($sql3);
    if (mysql_num_rows($result3) == 0) {
      $sql4 = "INSERT INTO combos (combo_id, more_info) VALUES ('$combo1','Item Name')";
      $result4 = mysql_query($sql4);
    }
  }
}

When table test_a has the values 1,2,3, and 4 this script inserts: 1_1 1_2 1_3 1_4 2_2 2_3 2_4 3_3 3_4 4_4

Bu herhangi bir bellek sorunları olmamalıdır. Eğer büyük bir veritabanı varsa php zaman sınırı ile bir sorunu çalıştırmak olsa

İşte benim diğer bir cevap olarak aynı kavram ama tüm SQL formatında.

INSERT INTO combos (combo_id, more_info) 
  SELECT CONCAT_WS("_",t1.id,t2.id), "item_name" 
  FROM test_a t1, test_a t2 
  WHERE NOT EXISTS (SELECT * FROM combos WHERE combo_id = CONCAT_WS("_",t1.id,t2.id))
    AND NOT EXISTS (SELECT * FROM combos WHERE combo_id = CONCAT_WS("_",t2.id,t1.id))

Eğer db yere gelen ITEM_NAME alabilirsiniz varsayarsak, bu muhtemelen en hızlı ve en yoğun bellek çözüm olacaktır. Ben şu anda 1000 civarında kimlikleri bir test çalıştırıyorum. Bittiği zaman ben bu güncelleme olacak.

Evet. Sen hepsini yinelemek gerekirse Kodları / yeniden bunları yineleme ya da Grey kombinasyonun lexicographical indeksi saklamak ve kullanabilirsiniz.

"Algorithm 515: Generation of a Vector from the Lexicographical Index"; Buckles, B. P., and Lybanon, M. ACM Transactions on Mathematical Software, Vol. 3, No. 2, June 1977.: bir göz atın

Ben C içine here, tercüme ve daha here tarif ettik.

(Eğer dize birleştirme kullanmak eğer sen değilsin ki) otomatik olarak bilgi tutarlılığını zorlamak gerek yoksa, her onlara bir dizin (0-84) vermek, 85 öğeler için bir tablo kullanın ve temsil etmek için ikinci bir tablo kullanın sayısında her bit pozisyonu bir öğe gösteren sayısal bir veri türünü kullanarak öğeleri belirli bir set. (Örneğin, 000001101 ürün, 0, 2, temsil eder, ve 3)

64 daha fazla öğe için birden fazla alanı içine bölmek zorunda, ya da bir BLOB ya da bir dize (gack!) kullanabilirsiniz.

Bir birincil anahtar alanı olarak kullanmak durumunda olmayan çiftleri zorlayabilir.

hafıza değişimi artırmak için

memory_limit = 512M in your php.ini
or
ini_set('memory_limit', '512M') in your php script
or
php_value memory_limit 512M in your .htaccess