ตัวดำเนินการ tilde ใน Python


199

การใช้ตัวดำเนินการ tilde ใน Python คืออะไร

สิ่งหนึ่งที่ฉันคิดได้คือทำบางสิ่งในทั้งสองด้านของสตริงหรือรายการเช่นตรวจสอบว่าสตริงเป็น palindromic หรือไม่:

def is_palindromic(s):
    return all(s[i] == s[~i] for i in range(len(s) / 2)) 

การใช้งานที่ดีอื่น ๆ


11
โปรดทราบว่าตัวดำเนินการส่วนเสริมที่~นำมาใช้โดยวิธีพิเศษ__invert__นั้นไม่เกี่ยวข้องกับตัวnotดำเนินการซึ่งจะลบล้างค่าที่ส่งคืนโดย __bool__(หรือ__nonzero__ใน 2.x) ตามหลักเหตุผล นอกจากนี้ยังเป็นที่ไม่เกี่ยวข้องกับผู้ประกอบการปฏิเสธเอกดำเนินการโดย- __neg__ตัวอย่างเช่น~True == -2ซึ่งไม่ใช่Falseหรือเท็จและ-False == 0ซึ่งยังคงเป็นเท็จ
Eryk Sun

@eryksun แม้ว่าสิ่งที่คุณพูดถูกต้อง ( -False==0) มันสับสนเพราะคุณกำลังพูดถึง~และ~False == -1ที่ไม่ได้เป็นเท็จ
Guilherme de Lazari

3
@GuilhermedeLazari ตัวอย่างที่สองคือการเปรียบเทียบกับการปฏิเสธทางคณิตศาสตร์ ( __neg__) อาจเป็นไปได้ว่าฉันควรใช้อย่างต่อเนื่องTrueเช่น-True == -1ซึ่งไม่ใช่ -2 หรือFalseหรือเท็จซึ่งเชื่อมโยงกลับไปยัง~Trueผลลัพธ์อย่างชัดเจนยิ่งขึ้นและการลบล้างเลขคณิตของ a boolนั้นแตกต่างจากการปฏิเสธเชิงตรรกะ ฉันไม่ได้พยายามที่จะลึก ฉันเพิ่งจะเน้นการดำเนินงาน 3 ครั้งและวิธีการพิเศษที่บางครั้งอาจทำให้สับสน
Eryk Sun

คำตอบ:


192

มันเป็นโอเปอเรเตอร์ unary (รับอาร์กิวเมนต์เดี่ยว) ที่ยืมมาจาก C ซึ่งชนิดข้อมูลทั้งหมดเป็นวิธีการตีความไบต์ที่แตกต่างกัน มันคือการดำเนินการ "invert" หรือ "complement" ซึ่งบิตทั้งหมดของข้อมูลอินพุตจะถูกย้อนกลับ

ใน Python สำหรับจำนวนเต็มบิตของการเป็นตัวแทน twos-complementของจำนวนเต็มจะถูกกลับรายการ (เช่นเดียวกับในb <- b XOR 1แต่ละบิต) และผลลัพธ์จะถูกตีความอีกครั้งเป็นจำนวนเต็มทวีคูณ ดังนั้นสำหรับจำนวนเต็มเทียบเท่ากับ~x(-x) - 1

รูปแบบ reified ของผู้ประกอบการให้เป็น~ operator.invertเพื่อสนับสนุนผู้ประกอบการนี้ในชั้นเรียนของคุณเองให้__invert__(self)วิธีการ

>>> import operator
>>> class Foo:
...   def __invert__(self):
...     print 'invert'
...
>>> x = Foo()
>>> operator.invert(x)
invert
>>> ~x
invert

คลาสใดก็ตามที่มีความหมายที่จะมี "ส่วนประกอบ" หรือ "อินเวอร์ส" ของอินสแตนซ์ที่เป็นอินสแตนซ์ของคลาสเดียวกันนั้นก็เป็นตัวเลือกที่เป็นไปได้สำหรับโอเปอเรเตอร์อินเวิร์ช อย่างไรก็ตามการบรรทุกเกินพิกัดอาจทำให้เกิดความสับสนหากนำไปใช้ในทางที่ผิดดังนั้นโปรดตรวจสอบให้แน่ใจก่อนที่จะส่ง__invert__วิธีการไปยังชั้นเรียนของคุณ (โปรดทราบว่าไบต์สตริง [อดีต: '\xff'] ไม่รองรับโอเปอเรเตอร์นี้แม้ว่าจะมีความหมายในการสลับบิตทั้งหมดของไบต์สตริง)


16
คำอธิบายที่ดี แต่เป็นคำเตือน - ข้อสงวนสิทธิ์ความปลอดภัยทั้งหมดสำหรับผู้ปฏิบัติงานมีการใช้งานเกินพิกัดที่นี่ - ไม่ใช่ความคิดที่ดีเว้นแต่จะเหมาะกับใบเรียกเก็บเงินอย่างสมบูรณ์แบบ
Eli Bendersky

ข้อเสนอแนะของอีไลถูกรวมเข้าไว้ในคำตอบในวรรคสุดท้าย
wberry

91

~เป็นตัวดำเนินการbitwise complementใน python ซึ่งคำนวณเป็นหลัก-x - 1

ดังนั้นตารางจะเป็นอย่างไร

i  ~i  
0  -1
1  -2
2  -3
3  -4 
4  -5 
5  -6

ดังนั้นi = 0มันจะเปรียบเทียบs[0]กับs[len(s) - 1]สำหรับi = 1, กับs[1]s[len(s) - 2]

สำหรับคำถามอื่น ๆ ของคุณนี้จะมีประโยชน์สำหรับช่วงของแฮ็บิต


26

นอกเหนือจากการเป็นผู้ประกอบการระดับบิตสมบูรณ์, ~นอกจากนี้ยังสามารถช่วยให้ย้อนกลับบูลค่าแม้ว่ามันจะไม่ธรรมดาประเภทที่นี่มากกว่าที่คุณควรใช้boolnumpy.bool_


นี่คือคำอธิบายใน

import numpy as np
assert ~np.True_ == np.False_

การย้อนกลับของค่าตรรกะอาจมีประโยชน์ในบางครั้งเช่น~ตัวดำเนินการด้านล่างจะใช้ในการล้างชุดข้อมูลของคุณและส่งกลับคอลัมน์โดยไม่มี NaN

from numpy import NaN
import pandas as pd

matrix = pd.DataFrame([1,2,3,4,NaN], columns=['Number'], dtype='float64')
# Remove NaN in column 'Number'
matrix['Number'][~matrix['Number'].isnull()]

numpy.NaNnumpy.floatดูเหมือนว่าจะได้รับการกำหนดให้เป็น ถ้าฉันพยายาม~numpy.NaNหลามบ่นว่าผู้ประกอบการเอกไม่ได้กำหนดไว้สำหรับประเภท~ numpy.float
M.Herzkamp

2
@ M.Herzkamp ถูกต้อง NaN, + Inf และ -Inf เป็นกรณีพิเศษของตัวเลขทศนิยม การแปลงบิตของจำนวนจุดลอยตัวจะทำให้เกิดผลลัพธ์ที่ไร้สาระดังนั้น Python จึงไม่อนุญาต นั่นเป็นเหตุผลที่คุณต้องโทรหา. isnull () หรือ np.isnan () บนอาเรย์ข้อมูลของคุณก่อนแล้วจึงกลับค่าบูลีนที่ได้
geofflee

7
โปรดทราบว่า~Trueผลลัพธ์จะส่งผลใน-2ขณะที่~np.True_ผลลัพธ์แบบบูลลีFalse
Christian Herenz

เคล็ดลับที่ดี! ฉันเห็นมันใช้ที่นี่เพื่อจัดเรียงชุดข้อมูล: github.com/yu4u/age-gender-estimation/blob/master/create_db.py
mLstudent33

19

หนึ่งควรทราบว่าในกรณีของการจัดทำดัชนีอาร์เรย์จำนวนarray[~i] reversed_array[i]มันสามารถเห็นได้ว่าเป็นดัชนีเริ่มต้นจากจุดสิ้นสุดของอาร์เรย์:

[0, 1, 2, 3, 4, 5, 6, 7, 8]
    ^                 ^
    i                ~i

2
ส่วนใหญ่เป็นเพราะค่าที่มาจาก~i(เช่นค่าลบ) ทำหน้าที่เป็นจุดเริ่มต้นสำหรับดัชนีอาร์เรย์ที่หลามยอมรับอย่างมีความสุขทำให้ดัชนีห่อรอบและเลือกจากด้านหลัง
กรีด

4

numpy/pandasเวลาเท่านั้นที่ฉันเคยใช้วิธีนี้ในการปฏิบัติอยู่กับ ยกตัวอย่างเช่นกับวิธี.isin() dataframe

ในเอกสารพวกเขาแสดงตัวอย่างพื้นฐานนี้

>>> df.isin([0, 2])
        num_legs  num_wings
falcon      True       True
dog        False       True

แต่ถ้าคุณต้องการแถวทั้งหมดที่ไม่ได้อยู่ใน [0, 2]

>>> ~df.isin([0, 2])
        num_legs  num_wings
falcon     False       False
dog        True        False

2

ผมได้รับการแก้ปัญหานี้ปัญหา leetcodeและฉันมาข้ามนี้ทางออกที่สวยงามโดยผู้ใช้ชื่อZitao วัง

ปัญหาจะเป็นเช่นนี้สำหรับแต่ละองค์ประกอบในอาเรย์ที่กำหนดค้นหาผลิตภัณฑ์ของจำนวนที่เหลือทั้งหมดโดยไม่ต้องใช้การแบ่งและในO(n)เวลา

ทางออกมาตรฐานคือ:

Pass 1: For all elements compute product of all the elements to the left of it
Pass 2: For all elements compute product of all the elements to the right of it
        and then multiplying them for the final answer 

วิธีแก้ปัญหาของเขาใช้เพียงหนึ่งเดียวสำหรับการวนซ้ำโดยใช้ เขาคำนวณผลิตภัณฑ์ด้านซ้ายและผลิตภัณฑ์ที่ถูกต้องได้ทันที~

def productExceptSelf(self, nums):
    res = [1]*len(nums)
    lprod = 1
    rprod = 1
    for i in range(len(nums)):
        res[i] *= lprod
        lprod *= nums[i]
        res[~i] *= rprod
        rprod *= nums[~i]
    return res

-2

นี่คือการใช้งานเล็กน้อยคือตัวหนอน ...

def split_train_test_by_id(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio)) 
    return data.loc[~in_test_set], data.loc[in_test_set]

รหัสข้างต้นมาจาก "Hands On Machine Learning"

คุณใช้เครื่องหมายตัวหนอน (~ เครื่องหมาย) เป็นทางเลือกแทน - เครื่องหมายดัชนี

เช่นเดียวกับที่คุณใช้ลบ - สำหรับดัชนีจำนวนเต็ม

อดีต)

array = [1,2,3,4,5,6]
print(array[-1])

เป็นสิ่งที่เป็น

print(array[~1])

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.