[英]How to check whether two lists are circularly identical in Python
例如,我有以下列表:
a[0] = [1, 1, 1, 0, 0]
a[1] = [1, 1, 0, 0, 1]
a[2] = [0, 1, 1, 1, 0]
# and so on
它們似乎不同,但是如果假定起點和終點相連,則它們在循環上是相同的。
問題是,每個列表的長度為55,並且僅包含三個1和52個零。 如果沒有循環條件,則有26,235(55選擇3)個列表。 但是,如果存在條件“循環”,則存在大量循環相同的列表
目前,我通過以下方式循環檢查身份:
def is_dup(a, b):
for i in range(len(a)):
if a == list(numpy.roll(b, i)): # shift b circularly by i
return True
return False
在最壞的情況下,此功能需要55次循環移位操作。 並且有26,235個列表可以相互比較。 簡而言之,我需要55 * 26,235 *(26,235-1)/ 2 = 18,926,847,225個計算。 大約有20 Giga!
有什么好方法可以減少計算量嗎? 還是支持循環的任何數據類型?
首先,這可以根據列表的長度在O(n)
中完成。您會注意到,如果將列表重復2次( [1, 2, 3]
)將為[1, 2, 3, 1, 2, 3]
那么您的新列表肯定會包含所有可能的循環列表。
因此,您所需要做的就是檢查您要搜索的列表是否在起始列表的2倍之內。 在python中,您可以通過以下方式實現此目的(假設長度相同)。
list1 = [1, 1, 1, 0, 0]
list2 = [1, 1, 0, 0, 1]
print ' '.join(map(str, list2)) in ' '.join(map(str, list1 * 2))
關於我的oneliner的一些解釋: list * 2
會將列表與其自身組合, map(str, [1, 2])
將所有數字轉換為字符串,而' '.join()
將轉換數組['1', '2', '111']
轉換為字符串'1 2 111'
。
正如某些人在評論中指出的那樣,oneliner可能會給出一些誤報,因此涵蓋了所有可能的極端情況:
def isCircular(arr1, arr2):
if len(arr1) != len(arr2):
return False
str1 = ' '.join(map(str, arr1))
str2 = ' '.join(map(str, arr2))
if len(str1) != len(str2):
return False
return str1 in str2 + ' ' + str2
PS1談到時間復雜度時,值得注意的是O(n)
如果子串中可以找到將達到O(n)
時間。 它並非總是如此,並且取決於您所用語言的實現方式( 盡管可能可以例如在線性時間KMP中完成 )。
PS2對於那些害怕字符串操作的人,由於這個事實,他們認為答案並不理想。 重要的是復雜性和速度。 該算法可能在O(n)
時間和O(n)
空間中運行,這使其比O(n^2)
域中的任何算法都要好得多。 要親自查看,可以運行一個小的基准測試(創建一個隨機列表會彈出第一個元素,並將其附加到末尾,從而創建一個循環列表。您可以自行進行操作)
from random import random
bigList = [int(1000 * random()) for i in xrange(10**6)]
bigList2 = bigList[:]
bigList2.append(bigList2.pop(0))
# then test how much time will it take to come up with an answer
from datetime import datetime
startTime = datetime.now()
print isCircular(bigList, bigList2)
print datetime.now() - startTime # please fill free to use timeit, but it will give similar results
在我的機器上0.3秒。 不太長。 現在嘗試將此與O(n^2)
解決方案進行比較。 在進行比較時,您可以從美國到澳大利亞旅行(很可能乘游輪旅行)
在Python中沒有足夠的知識來以您所請求的語言來回答這個問題,但是在C / C ++中,給定您問題的參數,我會將零和一轉換為位,然后將它們壓入uint64_t的最低有效位。 這樣一來,您就可以比較所有55位-1個時鍾。
速度極快,整個過程都可以放入片上緩存(209,880字節)。 僅在CPU的寄存器中提供對所有55個列表成員同時右移的硬件支持。 同時比較所有55個成員時也是如此。 這樣可以將問題一對一地映射到軟件解決方案。 (並使用SIMD / SSE 256位寄存器,如果需要,最多可使用256個成員),因此,代碼對於讀者而言立即顯而易見。
您也許可以在Python中實現此功能,但我只是不太了解它是否可能或性能如何。
睡在上面之后,一些事情變得顯而易見,並且一切都變得更好。
1.)使用位旋轉循環鏈接列表是如此容易,以至於Dali不需要非常巧妙的技巧。 在64位寄存器中,標准移位將非常簡單地完成旋轉,並通過使用算術而非位操作來使這一切對Python更友好。
2.)使用2分頻可以輕松完成移位。
3.)通過模2可以很容易地檢查列表末尾的0或1。
4.)通過從2的尾部將0從列表的尾部“移動”到列表的頭部,這是因為,如果實際移動了0,則將使第55位為false,這已經是絕對不做的了。
5.)將a從末尾“ 1”移動到列表的頭部可以通過除以2並加上18,014,398,509,481,984-這是通過將第55位標記為true並將其余所有標記為false來創建的值。
6.)如果在任何給定的旋轉之后,錨點與組成的uint64_t的比較為TRUE,則中斷並返回TRUE。
我會將整個列表數組直接轉換為uint64_ts數組,以避免重復進行轉換。
在花了幾個小時嘗試優化代碼之后,研究了匯編語言,我能夠將運行時節省20%。 我還應該補充說,O / S和MSVC編譯器也在昨天中午更新。 無論出於何種原因,C編譯器生成的代碼質量在更新(11/15/2014)后都得到了顯着改善。 現在,運行時間約為70個時鍾,約17納秒 ,可以在12.5秒內完成並比較錨環與測試環的所有55圈,並將所有環的NxN與其他環進行比較。
這段代碼是如此緊張,除了4個寄存器外,其余99%的時間都無所事事。 匯編語言幾乎逐行匹配C代碼。 非常容易閱讀和理解。 如果有人自學的話,這是一個很棒的組裝項目。
硬件是Hazwell i7,MSVC 64位,全面優化。
#include "stdafx.h"
#include "stdafx.h"
#include <string>
#include <memory>
#include <stdio.h>
#include <time.h>
const uint8_t LIST_LENGTH = 55; // uint_8 supports full witdth of SIMD and AVX2
// max left shifts is 32, so must use right shifts to create head_bit
const uint64_t head_bit = (0x8000000000000000 >> (64 - LIST_LENGTH));
const uint64_t CPU_FREQ = 3840000000; // turbo-mode clock freq of my i7 chip
const uint64_t LOOP_KNT = 688275225; // 26235^2 // 1000000000;
// ----------------------------------------------------------------------------
__inline uint8_t is_circular_identical(const uint64_t anchor_ring, uint64_t test_ring)
{
// By trial and error, try to synch 2 circular lists by holding one constant
// and turning the other 0 to LIST_LENGTH positions. Return compare count.
// Return the number of tries which aligned the circularly identical rings,
// where any non-zero value is treated as a bool TRUE. Return a zero/FALSE,
// if all tries failed to find a sequence match.
// If anchor_ring and test_ring are equal to start with, return one.
for (uint8_t i = LIST_LENGTH; i; i--)
{
// This function could be made bool, returning TRUE or FALSE, but
// as a debugging tool, knowing the try_knt that got a match is nice.
if (anchor_ring == test_ring) { // test all 55 list members simultaneously
return (LIST_LENGTH +1) - i;
}
if (test_ring % 2) { // ring's tail is 1 ?
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 1, set head to 1 to simulate wrapping
test_ring += head_bit;
} else { // ring's tail must be 0
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 0, doing nothing leaves head a 0
}
}
// if we got here, they can't be circularly identical
return 0;
}
// ----------------------------------------------------------------------------
int main(void) {
time_t start = clock();
uint64_t anchor, test_ring, i, milliseconds;
uint8_t try_knt;
anchor = 31525197391593472; // bits 55,54,53 set true, all others false
// Anchor right-shifted LIST_LENGTH/2 represents the average search turns
test_ring = anchor >> (1 + (LIST_LENGTH / 2)); // 117440512;
printf("\n\nRunning benchmarks for %llu loops.", LOOP_KNT);
start = clock();
for (i = LOOP_KNT; i; i--) {
try_knt = is_circular_identical(anchor, test_ring);
// The shifting of test_ring below is a test fixture to prevent the
// optimizer from optimizing the loop away and returning instantly
if (i % 2) {
test_ring /= 2;
} else {
test_ring *= 2;
}
}
milliseconds = (uint64_t)(clock() - start);
printf("\nET for is_circular_identical was %f milliseconds."
"\n\tLast try_knt was %u for test_ring list %llu",
(double)milliseconds, try_knt, test_ring);
printf("\nConsuming %7.1f clocks per list.\n",
(double)((milliseconds * (CPU_FREQ / 1000)) / (uint64_t)LOOP_KNT));
getchar();
return 0;
}
在行之間閱讀時,聽起來好像您正在嘗試枚舉具有3個1和52個0的每個圓形等效類的字符串的一個代表。 讓我們從密集表示轉換為稀疏表示( range(55)
的三個數字的集合)。 在此表示中, s
乘以k
的循環移位由理解set((i + k) % 55 for i in s)
。 一個類中的字典最小代表總是包含位置0。給定一組{0, i, j}
且0 < i < j
,該類中其他最小的候選者是{0, j - i, 55 - i}
和{0, 55 - j, 55 + i - j}
。 因此,我們需要(i, j) <= min((j - i, 55 - i), (55 - j, 55 + i - j))
來使原件最小。 這是一些枚舉代碼。
def makereps():
reps = []
for i in range(1, 55 - 1):
for j in range(i + 1, 55):
if (i, j) <= min((j - i, 55 - i), (55 - j, 55 + i - j)):
reps.append('1' + '0' * (i - 1) + '1' + '0' * (j - i - 1) + '1' + '0' * (55 - j - 1))
return reps
重復第一個數組,然后使用Z算法 (O(n)時間)在第一個數組中找到第二個數組。
(注意:您不必物理地復制第一個數組。您可以在匹配期間進行環繞。)
Z算法的優點在於,與KMP,BM等相比,它非常簡單。
但是,如果您有雄心壯志,則可以在線性時間和恆定空間中進行字符串匹配-例如, strstr
可以做到這一點。 但是,實施它會更加痛苦。
緊隨Salvador Dali的非常聰明的解決方案之后,處理該問題的最佳方法是確保所有元素的長度相同,並且兩個LIST的長度相同。
def is_circular_equal(lst1, lst2):
if len(lst1) != len(lst2):
return False
lst1, lst2 = map(str, lst1), map(str, lst2)
len_longest_element = max(map(len, lst1))
template = "{{:{}}}".format(len_longest_element)
circ_lst = " ".join([template.format(el) for el in lst1]) * 2
return " ".join([template.format(el) for el in lst2]) in circ_lst
不知道這是快於或慢於薩爾瓦多·達利的答案中AshwiniChaudhary推薦的正則表達式解決方案的內容,該內容為:
import re
def is_circular_equal(lst1, lst2):
if len(lst2) != len(lst2):
return False
return bool(re.search(r"\b{}\b".format(' '.join(map(str, lst2))),
' '.join(map(str, lst1)) * 2))
假設您需要進行大量比較,那么在初次遍歷列表時將它們轉換為某種可以輕松比較的規范形式是否值得?
您是否要獲取一組圓形唯一列表? 如果是這樣,您可以在轉換為元組后將它們放入集合中。
def normalise(lst):
# Pick the 'maximum' out of all cyclic options
return max([lst[i:]+lst[:i] for i in range(len(lst))])
a_normalised = map(normalise,a)
a_tuples = map(tuple,a_normalised)
a_unique = set(a_tuples)
大衛·艾森斯塔德(David Eisenstat)未能對他的相似答案表示歉意。
您可以像這樣滾動一個列表:
list1, list2 = [0,1,1,1,0,0,1,0], [1,0,0,1,0,0,1,1]
str_list1="".join(map(str,list1))
str_list2="".join(map(str,list2))
def rotate(string_to_rotate, result=[]):
result.append(string_to_rotate)
for i in xrange(1,len(string_to_rotate)):
result.append(result[-1][1:]+result[-1][0])
return result
for x in rotate(str_list1):
if cmp(x,str_list2)==0:
print "lists are rotationally identical"
break
首先將每一個列表元素(在副本如有必要) 到旋轉的版本,是詞法最大。
然后對列表的結果列表進行排序(在原始列表位置保留索引)並統一排序后的列表,並根據需要在原始列表中標記所有重復項。
Sa帶@SalvadorDali觀察在b + b中任何a長度大小的切片中尋找a的匹配項的觀察,這是僅使用列表操作的解決方案。
def rollmatch(a,b):
bb=b*2
return any(not any(ax^bbx for ax,bbx in zip(a,bb[i:])) for i in range(len(a)))
l1 = [1,0,0,1]
l2 = [1,1,0,0]
l3 = [1,0,1,0]
rollmatch(l1,l2) # True
rollmatch(l1,l3) # False
第二種方法:[已刪除]
這不是一個完整的,獨立的答案,但在通過減少比較來進行優化的主題上,我也在考慮標准化的表示形式。
即,如果您輸入的字母為{0,1},則可以大大減少允許的排列數量。 將第一個列表旋轉為(偽)歸一化形式(考慮到問題中的分布,我將選擇其中一個1位之一在最左端,而0個位之一在最右端的一個)。 現在,在每次比較之前,以相同的對齊方式在可能的位置上依次旋轉其他列表。
例如,如果您總共有四個1位,則此對齊方式最多可以有4個排列,並且如果您具有相鄰1位的簇,則此簇中的每個附加位都會減少位置數。
List 1 1 1 1 0 1 0
List 2 1 0 1 1 1 0 1st permutation
1 1 1 0 1 0 2nd permutation, final permutation, match, done
這可以概括為較大的字母和不同的對齊方式。 主要挑戰是找到僅包含幾種可能表示形式的良好歸一化方法。 理想情況下,這將是具有單個唯一表示形式的適當規范化,但是鑒於問題,我認為這是不可能的。
進一步建立在RocketRoy的答案上:將所有列表預先轉換為無符號的64位數字。 對於每個列表,將其旋轉55位以找到最小的數值。
現在,每個列表都剩下一個無符號的64位值,您可以直接將其與其他列表的值進行比較。 不再需要函數is_circular_identical()。
(從本質上講,您為列表創建了一個不受列表元素輪換影響的標識值)如果列表中有任意多個ID,則該值甚至可以工作。
這與Salvador Dali的想法相同,但是不需要字符串轉換。 后面是相同的KMP恢復想法,以避免不可能的輪班檢查。 它們僅調用KMPModified(list1,list2 + list2)。
public class KmpModified
{
public int[] CalculatePhi(int[] pattern)
{
var phi = new int[pattern.Length + 1];
phi[0] = -1;
phi[1] = 0;
int pos = 1, cnd = 0;
while (pos < pattern.Length)
if (pattern[pos] == pattern[cnd])
{
cnd++;
phi[pos + 1] = cnd;
pos++;
}
else if (cnd > 0)
cnd = phi[cnd];
else
{
phi[pos + 1] = 0;
pos++;
}
return phi;
}
public IEnumerable<int> Search(int[] pattern, int[] list)
{
var phi = CalculatePhi(pattern);
int m = 0, i = 0;
while (m < list.Length)
if (pattern[i] == list[m])
{
i++;
if (i == pattern.Length)
{
yield return m - i + 1;
i = phi[i];
}
m++;
}
else if (i > 0)
{
i = phi[i];
}
else
{
i = 0;
m++;
}
}
[Fact]
public void BasicTest()
{
var pattern = new[] { 1, 1, 10 };
var list = new[] {2, 4, 1, 1, 1, 10, 1, 5, 1, 1, 10, 9};
var matches = Search(pattern, list).ToList();
Assert.Equal(new[] {3, 8}, matches);
}
[Fact]
public void SolveProblem()
{
var random = new Random();
var list = new int[10];
for (var k = 0; k < list.Length; k++)
list[k]= random.Next();
var rotation = new int[list.Length];
for (var k = 1; k < list.Length; k++)
rotation[k - 1] = list[k];
rotation[rotation.Length - 1] = list[0];
Assert.True(Search(list, rotation.Concat(rotation).ToArray()).Any());
}
}
希望有幫助!
簡化問題
(0,1)
1
s映射為一個計數來減少問題 0
s為負數 例
A = [ 1, 1, 1, 0, 0, 1, 1, 0 ]
B = [ 1, 1, 0, 1, 1, 1, 0, 0 ]
~
A = [ +3, -2, +2, -1 ]
B = [ +2, -1, +3, -2 ]
檢查流程
握力
lookup
和look-ahead
偽代碼
FUNCTION IS_DUPLICATE (LIST L1, LIST L2) : BOOLEAN
LIST A = MAP_LIST(L1)
LIST B = MAP_LIST(L2)
LIST ALPHA = LOOKUP_INDEX(B, A[0])
IF A.SIZE != B.SIZE
OR COUNT_CHAR(A, 0) != COUNT_CHAR(B, ALPHA[0]) THEN
RETURN FALSE
END IF
FOR EACH INDEX IN ALPHA
IF ALPHA_NGRAM(A, B, INDEX, 1) THEN
IF IS_DUPLICATE(A, B, INDEX) THEN
RETURN TRUE
END IF
END IF
END FOR
RETURN FALSE
END FUNCTION
FUNCTION IS_DUPLICATE (LIST L1, LIST L2, INTEGER INDEX) : BOOLEAN
INTEGER I = 0
WHILE I < L1.SIZE DO
IF L1[I] != L2[(INDEX+I)%L2.SIZE] THEN
RETURN FALSE
END IF
I = I + 1
END WHILE
RETURN TRUE
END FUNCTION
功能
MAP_LIST(LIST A):LIST
以新列表中的計數MAP_LIST(LIST A):LIST
MAP決定性元素
LOOKUP_INDEX(LIST A, INTEGER E):LIST
返回元素E
在列表A
存在的索引的列表
COUNT_CHAR(LIST A , INTEGER E):INTEGER
LIST A
元素E
次數
ALPHA_NGRAM(LIST A,LIST B,INTEGER I,INTEGER N):BOOLEAN
如果B[I]
在兩個方向上均等價於A[0]
N-GRAM
ALPHA_NGRAM(LIST A,LIST B,INTEGER I,INTEGER N):BOOLEAN
檢查
最后
如果列表大小將非常龐大,或者如果我們開始檢查周期的元素經常很高,則可以執行以下操作:
在第一個列表中查找頻率最低的項目以
增加n-gram N參數以降低通過線性檢查的可能性
有關列表的有效,快速計算的“規范形式”可以得出:
a
)必須介於18
到52
(含)之間。 將其重新編碼為0
到34
之間。 b
)必須介於0
到26
之間,但這並不重要。 52 - (a + b)
並且不添加任何信息 規范形式是整數b * 35 + a
,介於0
到936
之間(包括0
和936
),該整數非常緊湊(總共有477
圓形唯一列表)。
我寫了一個簡單的解決方案,它比較兩個列表,並為每次迭代增加(並包裝)比較值的索引。
我不太了解python,所以我用Java編寫了它,但是它非常簡單,因此應該很容易將其適應任何其他語言。
這樣,您還可以比較其他類型的列表。
public class Main {
public static void main(String[] args){
int[] a = {0,1,1,1,0};
int[] b = {1,1,0,0,1};
System.out.println(isCircularIdentical(a, b));
}
public static boolean isCircularIdentical(int[] a, int[]b){
if(a.length != b.length){
return false;
}
//The outer loop is for the increase of the index of the second list
outer:
for(int i = 0; i < a.length; i++){
//Loop trough the list and compare each value to the according value of the second list
for(int k = 0; k < a.length; k++){
// I use modulo length to wrap around the index
if(a[k] != b[(k + i) % a.length]){
//If the values do not match I continue and shift the index one further
continue outer;
}
}
return true;
}
return false;
}
}
正如其他人提到的那樣,一旦找到列表的標准化輪換,就可以對其進行比較。
這是執行此操作的一些工作代碼,基本方法是為每個列表查找歸一化的旋轉並進行比較:
請注意,此方法不依賴於數字,您可以傳入字符串列表(可以比較的任何值)。
我們知道我們希望列表以最小值開頭,而不是進行列表中列表搜索,因此我們可以遍歷最小值,直到找到哪個具有最低連續值為止,然后將其存儲以進行進一步比較直到我們擁有最好的。
計算索引時有很多機會提早退出,有關一些優化的詳細信息。
請注意,在Python中,列表中列表搜索可能會更快,但是我很想找到一種有效的算法-也可以在其他語言中使用該算法。 同樣,避免創建新列表也有一些優勢。
def normalize_rotation_index(ls, v_min_other=None):
""" Return the index or -1 (when the minimum is above `v_min_other`) """
if len(ls) <= 1:
return 0
def compare_rotations(i_a, i_b):
""" Return True when i_a is smaller.
Note: unless there are large duplicate sections of identical values,
this loop will exit early on.
"""
for offset in range(1, len(ls)):
v_a = ls[(i_a + offset) % len(ls)]
v_b = ls[(i_b + offset) % len(ls)]
if v_a < v_b:
return True
elif v_a > v_b:
return False
return False
v_min = ls[0]
i_best_first = 0
i_best_last = 0
i_best_total = 1
for i in range(1, len(ls)):
v = ls[i]
if v_min > v:
v_min = v
i_best_first = i
i_best_last = i
i_best_total = 1
elif v_min == v:
i_best_last = i
i_best_total += 1
# all values match
if i_best_total == len(ls):
return 0
# exit early if we're not matching another lists minimum
if v_min_other is not None:
if v_min != v_min_other:
return -1
# simple case, only one minimum
if i_best_first == i_best_last:
return i_best_first
# otherwise find the minimum with the lowest values compared to all others.
# start looking after the first we've found
i_best = i_best_first
for i in range(i_best_first + 1, i_best_last + 1):
if (ls[i] == v_min) and (ls[i - 1] != v_min):
if compare_rotations(i, i_best):
i_best = i
return i_best
def compare_circular_lists(ls_a, ls_b):
# sanity checks
if len(ls_a) != len(ls_b):
return False
if len(ls_a) <= 1:
return (ls_a == ls_b)
index_a = normalize_rotation_index(ls_a)
index_b = normalize_rotation_index(ls_b, ls_a[index_a])
if index_b == -1:
return False
if index_a == index_b:
return (ls_a == ls_b)
# cancel out 'index_a'
index_b = (index_b - index_a)
if index_b < 0:
index_b += len(ls_a)
index_a = 0 # ignore it
# compare rotated lists
for i in range(len(ls_a)):
if ls_a[i] != ls_b[(index_b + i) % len(ls_b)]:
return False
return True
assert(compare_circular_lists([0, 9, -1, 2, -1], [-1, 2, -1, 0, 9]) == True)
assert(compare_circular_lists([2, 9, -1, 0, -1], [-1, 2, -1, 0, 9]) == False)
assert(compare_circular_lists(["Hello" "Circular", "World"], ["World", "Hello" "Circular"]) == True)
assert(compare_circular_lists(["Hello" "Circular", "World"], ["Circular", "Hello" "World"]) == False)
請參閱: 此片段以獲取更多測試/示例。
您可以很容易地檢查列表A是否等於列表B在預期O(N)時間中的循環移位。
我將使用多項式哈希函數來計算列表A的哈希,以及列表B的每個循環移位。如果列表B的移位具有與列表A相同的哈希,則我將比較實際元素以查看它們是否相等。
之所以如此之快,是因為使用多項式哈希函數(這是非常常見的!),您可以在恆定時間內計算與上一個循環移位相比的每個循環移位的哈希,因此您可以為O()中的所有循環移位計算哈希N)時間。
它是這樣的:
假設B有N個元素,那么使用質數P的B的哈希為:
Hb=0;
for (i=0; i<N ; i++)
{
Hb = Hb*P + B[i];
}
這是評估P中的多項式的一種優化方法,等效於:
Hb=0;
for (i=0; i<N ; i++)
{
Hb += B[i] * P^(N-1-i); //^ is exponentiation, not XOR
}
注意如何將每個B [i]乘以P ^(N-1-i)。 如果我們將B左移1,則每個B [i]將乘以一個額外的P,第一個除外。 由於乘法分布在加法上,因此我們可以通過將整個哈希值乘以一次來乘以所有分量,然后為第一個元素固定因數。
B左移的哈希只是
Hb1 = Hb*P + B[0]*(1-(P^N))
第二個左移:
Hb2 = Hb1*P + B[1]*(1-(P^N))
等等...
注意:上面的所有數學運算都是以某些機器字長為模,並且您只需計算一次P ^ N。
要粘合到最pythonic的方式,請使用set!
from sets import Set
a = Set ([1, 1, 1, 0, 0])
b = Set ([0, 1, 1, 1, 0])
c = Set ([1, 0, 0, 1, 1])
a==b
True
a==b==c
True
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.