Aralıkları kullanan tablo için uygun veri yapısı

6 Cevap php

Şöyle bir tablo var:

       <22  23-27   
8-10   1.3   1.8
11-13  2.2   2.8
14-16  3.2   3.8

ve gider. Yani böyle bir değeri arama İstediklerim:

lookup(11,25)

ve bu durumda 2.8, cevap alıyorum. Bunun için kullanılacak en iyi veri yapısı nedir? Ben CSV formatında veri var.

PHP bu program arıyorum.

Teşekkür ederim.

6 Cevap

Ben kesinlikle bu iyi ya da en verimli veri yapısıdır iddia etmiyorum, ama bu çok yakından ham veri benzeyen iki boyutlu bir PHP diziye harita verilerini ediyorum nasıl:

$fp = fopen('data.csv', 'r');
$cols = fgetcsv($fp);
array_shift($cols); // remove empty first item
$data = array();
while ($row = fgetcsv($fp)) {
  list($min, $max) = explode('-', $row[0]);
  // TODO: Handle non-range values here (e.g. column header "<22")
  $data["$min-$max"] = array();
  for ($x = 0; $x < count($cols); $x++) {
    $data["$min-$max"][$cols[$x]] = $row[$x + 1];
  }
}

Daha sonra lookup fonksiyonu bazı ayrıştırma mantığı eklemek gerekiyordu:

function lookup($row, $col) {
  $return = null;
  // Loop through all rows
  foreach ($data as $row_name => $cols) {
    list($min, $max) = explode('-', $row_name);
    if ($min <= $row && $max >= $row) {
      // If row matches, loop through columns
      foreach ($cols as $col_name => $value) {
        // TODO: Add support for "<22"
        list($min, $max) = explode('-', $col_name);
        if ($min <= $col && $max >= $col) {
          $return = $value;
          break;
        }
      }
      break;
    }
  }
  return $return;
}

Ne iki boyutlu veri yapısını bir tür ilgilidir.

X "coordinates" being <22, 23-27
Y "coordinates" being ...

Bir iki boyutlu Array muhtemelen bu amaç için çalışacak.

Daha sonra aralıkları için özel X ve Y değerlerini haritasına bazı işlev gerekir, ama bu çok zor olmamalı.

Veritabanı yapısı:

values
------
value
x_range_start
x_range_end
y_range_start
y_range_end

Kod:

function lookup(x, y) {
    sql = "
    	SELECT * FROM values
    	WHERE
    		x >= x_range_start
    		AND
    		x <= x_range_end

    		AND
    		y >= y_range_start
    		AND
    		y <= y_range_end
    "

    /---/
}

Sizin veriler şöyle veritabanına eşlersiniz:

      <22  23-27   
8-10   1.3   1.8
11-13  2.2   2.8
14-16  3.2   3.8

(value, x start, x end, y start, y end)
1.3, 0, 22, 8, 10
1.8, 23, 27, 8, 10
2.2, 0, 22, 11, 13
...

Temelde x depolamak ve y ekseni tablosundaki her değer için başlangıç ​​ve bitiş numaraları.

Ben tabloda belirli adreslere içine aralıkları eşleştiren bir "hash" fonksiyonu ile 2 Boyutlu diziye kısmi değilim.

Yani temel veri yapısı 2 boyutlu bir dizi olacak:

    0     1   
0  1.3   1.8
1  2.2   2.8
2  3.2   3.8

Sonra iki işlevi yazarsınız:

int xhash(int);
int yhash(int);

Bu özgün argümanları almak ve diziye indeksler dönüştürmek. Yani xhash dönüşüm gerçekleştirir:

8-10    0
11-13   1
14-16   2

Son olarak, arama işlemi olur.

function lookup($x, $y)
{
  $xIndex = xhash($x);
  $yIndex = yhash($y);
  // Handle invalid indices!

  return $data[$xIndex][$yIndex];
}

Peki, diğer cevaplar hepsini almak için bir 2B döngü kullanarak anlamına gelir, 2B diziler kullanın. Hangi sizin aralıkları yaş aralıkları veya benzeri bir şey varsa, bir sorun (bir kaç yüz tekrarlamalar nedir?) Değil (orada çok yaş aralıkları! Sadece), ve sonlu olabilir. Lütfen aralıkları muazzam sayılara ölçek bekleniyor ise, karma harita üzerinde bir oyun en iyi bahis olabilir. Yani, yerine bir döngü, o zaman doğrudan aramalarını yapmak, ilgili aralığı içine herhangi bir sayı döner karma işlevi oluşturun. , O (1) erişim yerine O (n ^ 2) olur.

If (n <22) return 1 fonksiyonu karma (n) {: Yani karma işlevi gibi olabilir if (n <25) return 2; return -1; [(11) karma]}, ve sonra (vs 1, 2,) bu hash değerleri bakımından aralıkları belirtebilirsiniz, ve sonra sadece $ veri go [hash (25)]

basit seçenek: Her dizi 5 unsurdan oluşur dizilerin dizisini oluşturmak: Minx, MaxX, MINY, MAXY, değer, sizin durumunuzda olurdu

$data = array(
      array(8, 10, 0, 22, 1.3),
      array(8, 10, 23, 27, 1.8),
      array(11, 13, 0, 22, 2.2), etc

her element geçer ve min ve karşılaştıran bir döngü yazmak max argümanlarınızla değerleri:

 function find($x, $y) {
      foreach($data as $e) {
         if($x <= $e[0] && $x >= $e[1] && $y <= $e[2] && $y >= $e[3])
              return $e[4];
 }

küçük bir veri kümesi ile bu veri kümesi büyük eğer bir veritabanı kullanarak düşünmelisiniz, iyi çalışır.