2014-12-17 2 views
5

Ich habe eine 32-Bit-Ganzzahl für Bitmaske und ein Array mit 32 Werten verwendet. Wie erhält man nur die Werte aus dem Array, deren Indizes den Positionen der Nicht-Null-Bits in der Bitmaske entsprechen?Get Array-Werte basierend auf Bitmaske in PHP

Zum Beispiel sagen wir, dass die Bitmaske 49152 ist, die 1100000000000000 binär ist. Daher muss ich die Werte der Elemente mit den Indizes 14 und 15 aus dem Array nehmen.

Antwort

1

Hier einige PHP-Code für Sie, aber bitte beachten Sie, es ist ziemlich ineffizient. Ich habe diesen Algorithmus verwendet, weil:

  1. Es explizit ist und verwendet Worte eher als mathematische Tricks die Arbeit zu erledigen, und
  2. Arbeiten in Situationen, in denen Sie nicht eine zugrunde liegende Implementierung von 2s Ergänzung annehmen können, aber wollen immer noch so "denken". (versuchen Bitmasken in PHP 'Speichern' und denken, sie in JavaScript arbeiten)

Bitte lesen Sie die Kommentare und implementieren @Paebbels Lösung. Der Unterschied in der Leistung ist fast 7x, also nutze das nur, wenn es nicht sehr oft benutzt wird.

Er verwendet base_convert, um die Basis 10 Ganzzahl in Basis 2 zu konvertieren, teilt die Zeichenfolge in ein Zeichenarray auf, kehrt das Array um und iteriert dann nach 1s.

$mask = 49152; // 0xC000 

// Find which positions in the mask contain a '1' 
$bitArray = array_reverse(str_split(base_convert($mask, 10, 2))); 

foreach($bitArray as $k => $v) { 
    if($v) { 
     echo $k . " is a one\n"; 
    } 
} 

Output:

14 ist ein ein

15 ist ein ein

Als Funktion:

function extractElements($mask, array $input) 
{ 
    $output = array(); 
    $bitArray = array_reverse(str_split(base_convert($mask, 10, 2))); 

    foreach($bitArray as $k => $v) { 
     if($v && isset($input[$k])) { 
      $output[] = $input[$k]; 
     } 
    } 

    return $output; 
} 

$mask = 76; // 0x4C 
$input = [ 
    'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight' 
]; 

print_r(extractElements($mask, $input)); 

Output:

Array ( [0] => Drei 1 => Vier [2] => Sieben )

+0

Entschuldigung, aber diese Lösung verbraucht Massen von Speicher- und CPU-Zyklen für eine Aufgabe von einfachen Bitverschiebungen und Bit-Vergleichen. – Paebbels

+0

_Massen des Gedächtnisses_? Nicht schlecht für eine 32-Bit-Integer-Maske. Sofern Sie keine Echtzeitanforderungen (.. in PHP ..) haben oder Sie dies wiederholt aufrufen, ist diese Lösung sinnvoll. Sonst bin ich mir sicher, dass die Leute deine Antwort hilfreich finden werden. –

+0

Meine Lösung: 3 Wörter á 4 Bytes = 12 Bytes {m, j, i}, es hat keine Aufrufanweisungen. - Ihre Lösung konvertiert die Maske von int in string; verwendet eine Basiskonvertierung basierend auf doppelten Werten (String zu Double, Base Convert, zu String Conversion); Danach wird eine String-Operation (str_split) verwendet und schließlich eine String-Reverse-Operation. Dies sind nur die Anfangsküsten ... In jeder Iteration greifen Sie auf eine Hash-Liste zu und rufen eine Isset-Funktion für einen einfachen Bit-Vergleich auf. Ihr Code verwendet 35 Aufrufanweisungen. Speicher: Jedes Zeichen eines Zwischenstrings wird in 2 Bytes (UTF-16) => 64 Bytes gespeichert. – Paebbels

6

Sie müssen in 32 Schritten über Ihre Maske schleifen und es für '1' testen, wenn dieses Bit gesetzt ist, können Sie das Element in das resultierende Array kopieren.

Pseudo-Code:

m = 0x00000001 
j = 0 
for i in 0 to 31 loop 
    if ((mask & m) = m) then // bit is set in mask 
    result(j++) := input(i) 
    end if 
    m := m << 1  // shift left by 1 or multiply by 2 
end loop 
+0

Wie können Sie Jeff Lambert echten ** PHP ** Code kritisieren, wenn alle Sie bieten _pseudocode_ an, die die gepostete Frage nicht adressiert? –

+0

Wie Jeff bemerkte, ist mein vorgeschlagener Algorithmus (den er implementiert hat) 7x schneller! – Paebbels

+0

Das ist nicht einmal PHP. #JustSaying –