2012-03-25 20 views
2

這可能是一個非常愚蠢的問題,但它只是掠過我的腦海裏,我認爲這將是有趣的,肯定知道....在PHP(或任何語言)中,可以合併2個位掩碼,同時保持orignal位的「身份」?

因此,這裏的情景:

用戶有3個選擇每週的每一天:上午,下午和關閉。這些是相互排斥的選擇,所以沒有選擇在同一天同時處理AM和PM。

所以,如果我想保存自己的AM轉變和PM轉變爲獨立的位掩碼,並且用戶1選擇以下內容:

S M T W Th F Sa 
A P X A X P A 

我想有以下幾點:

$shifts['User1']['AM'] = 73; // 1001001 
$shifts['User1']['PM'] = 34; // 0100010 

現在,如果我只是想知道User1在哪一天工作過,我顯然可以這樣做:

$shifts['User1']['All'] = $shifts['User1']['AM'] | $shifts['User1']['PM']; 

甚至只是:

$shifts['User1']['All'] = $shifts['User1']['AM'] + $shifts['User1']['PM']; 

但如果我想要的最終結果從PM區分上午,東西的效果:

$shifts['User1']['AM'] = A00A00A; 
$shifts['User1']['PM'] = 0P000P0; 

從而使A和P公司都被認爲集,但

A00A00A | 0P000P0 = AP0A0PA; 

有沒有這樣做的常見方式,或者我在想這完全錯誤?

+2

有兩件事情浮現在腦海中:三元和普通老舊的這種類型的任務沒有使用位掩碼。 – Ryan 2012-03-25 02:22:16

+0

哦,在一天結束時,我確信我要麼保持它們分開,要麼使用其他邏輯推斷等等。但是As和Ps的圖像跳進了我的腦海,我認爲它可能是其中一個「不,愚蠢,現在它是如何工作的」或「呃,只是改變基數」,所以我不得不把它扔到那裏來確認。 – Anthony 2012-03-25 02:28:59

回答

1

要以二進制方式表示三個狀態,您需要2位。例如,你可以說:

PM = 01

AM = 10

OFF = 00

所以,現在你有這樣的:

A00A00A轉化爲10 00 00 10 00 00 10

0P000P0轉化爲00 01 00 00 00 01 00

應用按位或運算:

10 00 00 10 00 00 10 
00 01 00 00 00 01 00 
-------------------- 
10 01 00 10 00 01 10 
A P 0 A 0 P A 

你得到AP0A0PA,你想要的結果。

+0

我幾乎不願意給你答案,因爲我希望它會涉及更奇怪或複雜的東西。但是我如何測試某人是否在星期天工作?它可以是'01'或'10'。我是否總是檢查它是不是*'00'?我相信我會弄明白,但更明顯的建議是值得歡迎的。 – Anthony 2012-03-25 02:52:22

+0

我想你會以同樣的方式檢查它,就好像你在每個狀態只使用一位一樣。任何適用於第一種情況的邏輯也適用於第二種情況。檢查不是「00」是一個選項。 – 2012-03-25 02:56:49

+1

@Anthony:這真的是很好的答案,效率更高。爲了檢查週日是否有人在工作,你只需要執行'$ shift | 0b11000000000000'(如果星期日是列表中的第一天)。如果星期天沒有換班,你會得到'0'。 (當然代碼可能不起作用,這只是爲了告訴你如何檢查特定的日子) – Tadeck 2012-03-25 02:57:57

0

這裏有兩個選項。

  1. 交錯

    原位掩碼展開,而新的掩碼插入新的「漏洞」。

    APAPAPAPAPAPAP 
    
  2. 追加

    新的位掩碼附加到舊掩碼。

    AAAAAAAPPPPPPP 
    

前者更容易檢查/比較,而後者是關於速度更高效。

+0

那麼,一些維基比達閱讀吞嚥。然而,我不清楚,0的去向。我如何分散對方的「洞」? (很可能我錯過了實際的觀點)。 – Anthony 2012-03-25 02:40:47

+0

As和Ps不是* literal * As和Ps;如果是的話,它不會是一個掩碼。相反,它們代表0和1的位置。鑽洞不是一個微不足道的過程。這就是追加效率更高的原因。 – 2012-03-25 02:48:29

+0

哈!我知道他們不是字面上的,或者我首先會問這個問題總是愚蠢的。我只是認爲核心思想已經過去了(現在)。但我很高興這些漏洞並不是微不足道的。我以爲我錯過了一些非常基本的東西。 – Anthony 2012-03-25 02:57:40

1

要寫入二進制文字值:0b1001001或十六進制:0x49,而不是十進制:73

位圖只會給你真或假,所以沒有辦法通過將兩個位圖壓縮成一個來表示三個值(AM,PM,X)。

我認爲你正在考慮這個錯誤(其他人可能有一個我不能想到的更聰明的解決方案)。字符A,P,X的數組可能對此很有幫助。你可以合併數組(所以它與字符串不一樣)。

+0

我不想使用二進制文字符號(我開始,但回去),因爲它是新的和有點可怕的樣子(我認爲)。我仍然不知道爲什麼十六進制比符號小於十進制。但根據你的實際情況,我認爲你是對的。我很好奇XORing與非匹配/非傳統數字作爲一個想法,但一旦它們合併,我只能使用二進制數學來看工作/不工作,所以我留下了字符串或數組(除非這裏的其他人知道在base-n系統中按位使用一些令人驚異的方法)。 – Anthony 2012-03-25 02:38:20

+0

十六進制的優點是它的基數(即)每個數字都相當於四位數的二進制數,因此可以將每個二進制位隔離開來。 – Paul 2012-03-25 02:43:45

1

是的,這是可能的。見下面的例子在Python:

>>> class WorkShift(str): 
    def __or__(self, val): 
     def shift_calc(x, y): 
      return x if x != '0' else y 
     return WorkShift(''.join(map(shift_calc, self, val))) 

>>> WorkShift('A00A00A') | WorkShift('0P000P0') 
'AP0A0PA' 

是否回答你的問題?

Ps。我使用了Python,因爲你明確聲明它可以是任何編程語言。我超載了|運營商。操作結果仍然是WorkShift的實例,因此您可以將其用於進一步處理。它也繼承自str,所以你可以把它作爲字符串使用。

EDIT:爲PHP

類似的解決方案,但沒有操作符重載,僅基於字符串處理:

<?php 

function shift_calc($x, $y) { 
    return $x != '0' ? $x : $y; 
}; 

function shift_sum($am, $pm) { 
    return implode(array_map('shift_calc', str_split($am), str_split($pm))); 
}; 

$result = shift_sum('A00A00A', '0P000P0'); 

其中$result是具有以下值的字符串: 「AP0A0PA」(請參閱證明:http://ideone.com/NbTEJ)。

+0

+1表示它可以完成。現在我只需要拿出我的逆向工程上限來確定它是否可以在PHP中複製。 – Anthony 2012-03-25 02:32:15

+1

@Anthony:是的,可以實施。查看PHP <5.3的示例(對於PHP> = 5.3,它會更好):http://ideone.com/NbTEJ – Tadeck 2012-03-25 02:39:33

+0

讓我把它複製到我的本地服務器,看看我能不能找出如何得到它在5.3更好(或者我永遠不會學習!)。 – Anthony 2012-03-25 02:45:53

1

minitech的評論是正確的。這是一個三元數字系統(因爲每個值有3個選項)。所以你可以這樣做:

$shifts['User1']['AM'] = '1001001'; // A00A00A 
$shifts['User1']['PM'] = '0200020'; // 0P000P0 

$all = intval($shifts['User1']['AM'], 3) + 
    intval($shifts['User1']['PM'], 3); 

echo base_convert($all, 10, 3); 
+0

這正是我想到的! (sorta)我不確定你是否可以改變基數,仍然得到相同的位置結果。這是否工作到第n個基數(或者與intval()和base_convert一樣高)?如果是這樣,似乎你只需要選擇的數量,乘以它的「行號」所設置的每一位,然後將它們全部使用總數加起來等。 – Anthony 2012-03-25 04:24:02

+0

是的,這是一個很好的通用思考方式。 – Paul 2012-03-25 04:56:32