0

この質問は疑似 PHP でコーディングされていますが、これは純粋に仮説であるため、どの言語で回答が得られるかは気にしません (Ruby :-P を除く)。実際、PHP は、この種のロジックを実行する言語としてはおそらく最悪です。残念ながら、私はこれまで一度も実行したことがないので、実際の例を提供することはできません。したがって、仮説的な答えは完全に受け入れられます。

基本的に、タスクを実行するオブジェクトがたくさんあります。この例では、各オブジェクトがインターネットからファイルをダウンロードするクラスであるとします。各オブジェクトは異なるファイルをダウンロードし、ダウンロードは並行して実行されます。明らかに、一部のオブジェクトは他のオブジェクトより先にダウンロードを終了する場合があります。データの実際の取得はスレッドで実行される場合がありますが、それはこの質問には関係ありません。

したがって、オブジェクトを次のように定義できます。

class DownloaderObject() {
    var $url = '';
    var $downloading = false;

    function DownloaderObject($v){ // constructor
        $this->url = $v;
        start_downloading_in_the_background(url=$this->$url, callback=$this->finished);
        $this->downloading = true;
    }

    function finished() {
        save_the_data_somewhere();
        $this->downloading = false;
        $this->destroy(); // actually destroys the object
    }
}

さて、これらのオブジェクトがたくさん実行されています。

$download1 = new DownloaderObject('http://somesite.com/latest_windows.iso');
$download2 = new DownloaderObject('http://somesite.com/kitchen_sink.iso');
$download3 = new DownloaderObject('http://somesite.com/heroes_part_1.rar');

そして、それらを配列に格納できます。

$downloads = array($download1, $download2, $download3);

したがって、ダウンロードでいっぱいの配列があります。

array(
  1 => $download1,
  2 => $download2,
  3 => $download3
)

そして、次のようにそれらを反復できます。

print('Here are the downloads that are running:');
foreach ($downloads as $d) {
    print($d->url . "\n");
}

さて、ダウンロード 2 が終了し、オブジェクトが破棄されたとします。これで、配列に 2 つのオブジェクトが含まれているはずです。

array(
  1 => $download1,
  3 => $download3
)

しかし、配列に穴があります!キー #2 は使用されていません。また、新しいダウンロードを開始したい場合、ダウンロードを配列のどこに挿入すればよいかわかりません。以下が機能する可能性があります。

$i = 0;
while ($i < count($downloads) - 1) {
    if (!is_object($downloads[$i])) {
        $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
    $i++;
}

ただし、それは非常に非効率的です (そしてwhile $i++ループは面倒です)。したがって、別のアプローチは、カウンターを保持することです。

function add_download($url) {
    global $downloads;
    static $download_counter;

    $download_counter++;
    $downloads[$download_counter] = new DownloaderObject($url);
}

それは機能しますが、配列にまだ穴があります。

array(
  1  => DownloaderObject,
  3  => DownloaderObject,
  7  => DownloaderObject,
  13 => DownloaderObject
)

それは醜いです。しかし、それは受け入れられますか?配列を「最適化」する必要がありますか。つまり、空白を削除するためにキーを再配置しますか?

または、私が知っておくべき別のプログラム構造がありますか? 何かを追加したり、何かを削除したり、変数のキーを参照したり、反復処理したりできる構造が欲しいのですが、それは配列ではありません。そのようなものは存在しますか?

私は何年もコーディングを行ってきましたが、この質問は何年にもわたって私を悩ませてきました。私はまだ答えを知りません. これは一部のプログラマーにとっては明白かもしれませんが、私にとっては非常に些細なことではありません。

4

6 に答える 6

4

PHP の「連想配列」の問題は、それらが配列ではなく、ハッシュマップであることです。そこに穴があいてもまったく問題ありません。リンクされたリストも見るかもしれませんが、ハッシュマップはあなたがしていることに完全に適しているようです。

于 2008-12-08T07:07:00.653 に答える
2

ダウンローダの配列を維持しているのは何ですか?

ダウンローダの終了時に通知されるクラスに配列をカプセル化すると、破棄されたオブジェクトへの古い参照について心配する必要がなくなります。

このクラスは、配列の編成を内部的に管理し、配列というよりイテレータに似たインターフェイスをユーザーに提示できます。

于 2008-12-08T08:00:18.660 に答える
1

「$i++ ループ」は面倒ですが、for ループを使用するとコードがより明確になるためです。

$i = 0;
while ($i < count($downloads) - 1) {
    if (!is_object($downloads[$i])) {
       $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
    $i++;
}

なる

for($i=0;$i<count($downloads)-1;++$i){
    if (!is_object($downloads[$i])) {
        $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
}
于 2008-12-08T07:07:30.327 に答える
1

C# の観点からすると、最初に考えたのは、配列とは異なるデータ構造が必要だということです。より高いレベルのデータ構造を使用して問題を考える必要があります。おそらく、キュー、リスト、またはスタックの方が目的に適しているでしょうか?

于 2008-12-08T07:10:58.837 に答える
1

あなたの質問に対する簡単な答えは、PHP では配列がほとんどすべてに使用されており、他のデータ構造を使用することはめったにないということです。配列インデックスに穴があっても心配する必要はありません。Java などの他のプログラミング言語では、より多様なデータ構造のセット (セット、ハッシュ、リスト、ベクトルなど) を選択できます。Array と DownloaderObject クラスの間のより緊密な相互作用も必要になるようです。オブジェクト $download2 自体に「destroyed()」があるという理由だけで、配列はそのオブジェクトへの参照を維持します。

于 2008-12-08T07:45:51.590 に答える
0

回答者の相対的な経験を反映した、この質問に対するいくつかの良い回答。どうもありがとうございました — 彼らは非常に教育的であることがわかりました.

この質問を投稿したのは約 3 年前です。後から考えると、その分野での私の知識が著しく不足していたことがわかります。私が抱えていた最大の問題は、要素を任意にポップする機能を持たない PHP の観点から考えていたことです。この質問に対する他の回答が発見するのに役立ったのは、根本的に優れたモデルは「リンクされたリスト」であるということです。

C については、コード サンプル (ここに投稿するには多すぎる) を含むリンク リストに関するブログ投稿を書きましたが、元の質問のユース ケースをきちんと満たしています。

PHP の場合、リンクされたリストの実装がここに表示されますが、これは試したことはありませんが、上記を処理する正しい方法でもあると想像してください。

興味深いことに、Python のリストpop()には、 PHP の とは異なりarray_pop()、任意の要素をポップしてすべてを順番に保持できるメソッドが含まれています。例えば:

>>> x = ['baa', 'ram', 'ewe'] # our starting point
>>> x[1]                      # making sure element 1 is 'ram'
'ram'
>>> x.pop(1)                  # let's arbitrarily pop an element in the middle
'ram'
>>> x                         # the one we popped ('ram') is now gone
['baa', 'ewe']
>>> x[1]                      # and there are no holes: item 2 has become item 1
'ewe'
于 2008-12-09T13:03:46.330 に答える