Bir dizinin her n öğe seçme

8 Cevap php

Ne büyük bir dizi her n öğeyi seçmek için en efficient yolu olurdu? Bunu yapmak için bir 'akıllı' bir yolu var mı yoksa tek yolu döngü nedir?

Dikkat etmeniz gereken bazı noktalar:

  • Dizi 130 000 öğeleri ile oldukça büyük
  • Her 205 öğe seçmek zorunda
  • Öğeler sayısal endeksli değildir, bu yüzden for($i = 0; $i <= 130000; $i += 205) çalışmaz

Şimdiye kadar, bu ben ile geldim en etkili yöntem:

$result = array();
$i = 0;
foreach($source as $value) {

    if($i >= 205) {
        $i = 0;
    }

    if($i == 0) {
        $result[] = $value;
    }

    $i++;
}

Veya modulonun ile aynı:

$result = array();
$i = 0;
foreach($source as $value) {
    if($i % 205 == 0) {
        $result[] = $value;
    }
    $i++;
}

Bu yöntemler oldukça yavaş olabilir, geliştirmek için herhangi bir yolu var mı? Yoksa sadece burada tüyleri yarma am?

EDIT

İyi cevaplar çevresinde uygun açıklamalar ile, kabul edilen yanıt olarak en uygun almaya çalıştı. Teşekkürler!

8 Cevap

Bir foreach döngüsü karşılaştırma testlerine dayalı geniş bir dizi üzerinde hızlı yineleme sağlar. Biri loop unrolling ile sorunu çözmek istediği sürece ben ne var benzer bir şey ile sopa istiyorum.

Bu cevap daha hızlı koşmak gerekmektedir.

$result = array();
$i = 0;
foreach($source as $value) {
    if ($i++ % 205 == 0) {
        $result[] = $value;
    }
}

Ben test etmek için vaktim yok, ama sen ilk sayısal dizin, dizi @ Haim çözümü bir varyasyonu kullanmak mümkün olabilir. Bu benim önceki çözüm üzerinde herhangi kazançlar alabilirsiniz görmek için denemeye değer:

$result = array();
$source = array_values($source);
$count = count($source);
for($i = 0; $i < $count; $i += 205) {
    $result[] = $source[$i];
}

Bu büyük ölçüde fonksiyon array_values ​​optimize edilmiş ne kadar bağlı olacaktır. Çok iyi korkunç gerçekleştirebilir.

Try ArrayIterator::seek()

Ayrıca, birini kullanarak yeni Spl datastructures düz dizileri kullanarak daha iyi sonuçlar verebilmektedir.

i array_slice kullanmanızı öneririz

$count = count($array) ;
for($i=205;$i<$count;$i+=205){
    $result[] = array_slice($array,$i,1);
}

Bu sorunun çözümü, herhangi bir PHP sözdizimi ancak kod tasarım yalan değil düşünüyorum.

Siz, (uygulama için makul olmayabilir) dizi sayısal endeksli yaptığınız her 205 öğe takip, ya da yalnızca (her 205 öğe listesini önbelleğe) kez dizi aramak olabilir ya.

Aklımda, her 205 öğenin takip uygulamak daha kolay olacaktır. Sadece bir veritabanı veya bir şey tüm öğelerin sayısını tutmak istiyorum, ve her zaman bir öğe eklendiğinde, sayımı modülosunu kontrol edin. Başka bir 205 madde varsa, diziye eklemek. Ürün olsa silinir zaman için, bu yanıltıcıdır olacaktır. Tüm 205 öğeleri yeniden düzenlemek için yeniden kontrol tüm dizi gerekebilir.

Bunu yapmanız silinen öğenin başlar ve ileriye taşımak olabilir basit olurdu, ama yine bu sadece sayısal endeksli diziler için çalışacak - ve bu doğru olsaydı, size sadece yapardın, tüm ileriye taşımak olmazdı yeniden şekil dışarı biraz matematik.

  • Sayısal indeksleri - daha iyi uzun vadeli çözüm ama uygulamak zor
  • Uygulamak kolay, ama sen öğeleri silerken yine kirli almak gerekiyor - takip etmek
  • Önbelleğe alma öğeler - belki de, diğer iki çözümler için bu yapmalıyım, ama dizi muhtemelen yeniden yapmak o olurdu bu durumda, değiştirilmiş kadar kendi üzerinde, hızlı olurdu.

Bu gerçekten bir tıkanıklık varsa, bunu sayısal endeksli hale getirmek için tasarım yeniden düşünmek düşünebilirsiniz.

EDIT: Ya oluşturmak ve (insert ya da buna benzer bir şey de güncellenir) sadece 205 öğeleri ile ayrı bir dizi korumak.

  • İki boyutlu bir dizi oluşturmak [205] [N]
  • Diziye yük veri
  • Her N için 205 eleman erişin

Saçma gelebilir ama doğrudan bellek konumlarını erişmek ve herhangi bir karşılaştırma yapmazsanız yana tanım olarak, en hızlı olduğu olabilir.

Sen dizi imlecini hareket edemez, bir defada birden fazla görünüyor. Ben şahsen bu kullanmak:

reset($source);
$next = true;
while($next === true){
    $result[] = current($source);
    for(i=0;i<205;i++){
        $next = next($source);
    }
}

Birisi bir seferde sadece tek bir adımda birden dizi ibre daha taşıyabilirsiniz bir fonksiyonu bulmak varsa, daha iyi bir cevap olacaktır. Ben bu olsa iyi olduğunu düşünüyorum.

Sen array_keys sadece dizi anahtarları üzerinde çalışmak için kullanabilirsiniz.

$keys = array_keys($array);
for ($i=0, $n=min(count($keys), 130000); $i<$n; $i += 205) {
    $result[] = $array[$keys[$i]];
}