python - مكتبة - عكس سلسلة في بايثون




مكتبة اكواد بايثون (12)

لا يوجد بني في وظيفة reverse لكائن str Python. ما هي أفضل طريقة لتنفيذ هذه الطريقة؟

في حالة تقديم إجابة مختصرة للغاية ، يرجى توضيح كفاءتها. على سبيل المثال ، ما إذا كان كائن str يتم تحويله إلى كائن مختلف ، إلخ.


ما هي أفضل طريقة لتنفيذ وظيفة عكسية للسلاسل؟

تجربتي الخاصة مع هذا السؤال أكاديمية. ومع ذلك ، إذا كنت من المحترفين الذين يبحثون عن إجابة سريعة ، فاستخدم شريحة تتخطى -1 :

>>> 'a string'[::-1]
'gnirts a'

أو أكثر قابلية للقراءة (ولكن أبطأ بسبب عمليات البحث عن اسم الأسلوب وحقيقة أن الانضمام يشكل قائمة عند إعطاء str.join ) ، str.join :

>>> ''.join(reversed('a string'))
'gnirts a'

أو للقراءة وإعادة الاستخدام ، ضع الشريحة في إحدى الوظائف

def reversed_string(a_string):
    return a_string[::-1]

وثم:

>>> reversed_string('a_string')
'gnirts_a'

مزيد من الشرح

إذا كنت مهتمًا بالمعرض الأكاديمي ، فالرجاء مواصلة القراءة.

لا توجد وظيفة عكس مدمجة في كائن str في Python.

إليك بعض الأشياء حول سلاسل بايثون التي يجب عليك معرفتها:

  1. في بايثون ، تكون الجمل غير قابلة للتغيير . لا يؤدي تغيير سلسلة إلى تعديل السلسلة. يخلق واحدة جديدة.

  2. السلاسل قابلة للفصل. يمنحك تقسيم سلسلة أحرف سلسلة جديدة من نقطة واحدة في السلسلة ، إلى الخلف أو للأمام ، إلى نقطة أخرى ، بزيادات محددة. يأخذون تدوين شريحة أو كائن شريحة في منخفض:

    string[subscript]
    

ينشئ المقطع النصي شريحة من خلال تضمين نقطتين داخل الأقواس:

    string[start:stop:step]

لإنشاء شريحة خارج الأقواس ، ستحتاج إلى إنشاء كائن شريحة:

    slice_obj = slice(start, stop, step)
    string[slice_obj]

نهج قابل للقراءة:

في حين أن ''.join(reversed('foo')) يمكن قراءته ، فإنه يتطلب استدعاء طريقة سلسلة ، str.join ، على وظيفة أخرى تسمى ، والتي يمكن أن تكون بطيئة نسبيًا. لنضع هذا في وظيفة - سوف نعود إليه:

def reverse_string_readable_answer(string):
    return ''.join(reversed(string))

نهج معظم الاداء:

أسرع بكثير هو استخدام شريحة عكسية:

'foo'[::-1]

ولكن كيف يمكننا جعل هذا أكثر قابلية للقراءة ومفهومة لشخص أقل دراية بشرائح أو نية المؤلف الأصلي؟ لنقم بإنشاء كائن شريحة خارج تدوين المصاحبة ، وإعطائه اسمًا وصفيًا ، ثم تمريره إلى تدوين المصاحبة.

start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]

نفذ كوظيفة

لتنفيذ هذا بالفعل كدالة ، أعتقد أنه من الواضح دلاليًا بما يكفي لاستخدام اسم وصفي:

def reversed_string(a_string):
    return a_string[::-1]

والاستخدام هو ببساطة:

reversed_string('foo')

ماذا يريد معلمك على الأرجح:

إذا كان لديك مدرب ، فمن المحتمل أنك تريد أن تبدأ بسلسلة فارغة ، وأن تنشئ سلسلة جديدة من السلسلة القديمة. يمكنك القيام بذلك مع بناء الجملة النقي والحرفي باستخدام حلقة while:

def reverse_a_string_slowly(a_string):
    new_string = ''
    index = len(a_string)
    while index:
        index -= 1                    # index = index - 1
        new_string += a_string[index] # new_string = new_string + character
    return new_string

هذا أمر سيء نظريًا لأنه ، تذكر ، الأوتار غير قابلة للتغيير - لذلك في كل مرة يبدو فيها أنك تقوم بإلحاق حرف في new_string ، فإنه ينشئ نظريًا سلسلة جديدة في كل مرة! ومع ذلك ، يعرف CPython كيفية تحسين ذلك في حالات معينة ، والتي تكون هذه الحالة البسيطة.

افضل تمرين

من الناحية النظرية أفضل هو جمع سلاسل التشغيل الخاصة بك في قائمة ، والانضمام إليهم في وقت لاحق:

def reverse_a_string_more_slowly(a_string):
    new_strings = []
    index = len(a_string)
    while index:
        index -= 1                       
        new_strings.append(a_string[index])
    return ''.join(new_strings)

ومع ذلك ، وكما سنرى في التوقيت أدناه لـ CPython ، فإن هذا يستغرق وقتًا أطول بالفعل ، لأن CPython يمكنها تحسين تسلسل السلسلة.

توقيت

وهنا توقيت:

>>> a_string = 'amanaplanacanalpanama' * 10
>>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string)))
10.38789987564087
>>> min(timeit.repeat(lambda: reversed_string(a_string)))
0.6622700691223145
>>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string)))
25.756799936294556
>>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string)))
38.73570013046265

يقوم CPython بتحسين سلسلة السلاسل ، في حين أن التطبيقات الأخرى قد لا :

... لا تعتمد على تنفيذ CPython الفعال لسلسلة السلاسل الموضعية للعبارات في النموذج a + = b أو a = a + b. هذا التحسين هش حتى في CPython (إنه يعمل فقط لبعض الأنواع) وليس موجودًا على الإطلاق في التطبيقات التي لا تستخدم refcounting. في الأجزاء الحساسة للأداء في المكتبة ، يجب استخدام نموذج '' .join () بدلاً من ذلك. سيضمن ذلك حدوث التسلسل في الوقت الخطي عبر عمليات التنفيذ المختلفة.


الإجابة السريعة (TL ، DR)

مثال

### example01 -------------------
mystring  =   'coup_ate_grouping'
backwards =   mystring[::-1]
print backwards

### ... or even ...
mystring  =   'coup_ate_grouping'[::-1]
print mystring

### result01 -------------------
'''
gnipuorg_eta_puoc
'''

إجابة مفصلة

خلفية

يتم توفير هذه الإجابة لمعالجة المخاوف التالية منodigity:

رائع. لقد شعرت بالرعب في البداية بسبب الحل الذي اقترحه باولو ، لكن ذلك أخذ مقعدًا خلفيًا للرعب الذي شعرت به عند قراءة التعليق الأول: "هذا أمرٌ رائع للغاية. وظيفة جيدة!" إنني أشعر بالانزعاج الشديد لأن مثل هذا المجتمع المشرق يفكر في استخدام مثل هذه الأساليب الخفيّة لشيء أساسي للغاية هو فكرة جيدة. لماذا ليس فقط s.reverse ()؟

مشكلة

  • سياق الكلام
    • بيثون 2.x
    • Python 3.x
  • سيناريو:
    • يريد المطور تحويل سلسلة
    • التحول هو عكس ترتيب جميع الشخصيات

حل

المزالق

  • قد يتوقع مطوّر البرامج شيئًا مثل string.reverse()
  • قد لا يكون الحل الاصطلاحي الأصلي (aka " pythonic ") قابلاً للقراءة للمطورين الجدد
  • قد يميل المطور إلى تطبيق الإصدار الخاص به من string.reverse() لتجنب تدوين الشريحة.
  • قد يكون إخراج تدوين الشريحة غير بديهي في بعض الحالات:
    • انظر على سبيل المثال ، example02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • مقارنة ب
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • مقارنة ب
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • قد تؤدي النتائج المختلفة للفهرسة في [-1] إلى إيقاف بعض المطورين

المنطق

للبيثون ظرف خاص يجب أن يكون على دراية به: الخيط هو نوع قابل iterable .

أحد string.reverse() المنطقية لاستبعاد طريقة string.reverse() هو إعطاء مطوري python حافزًا للاستفادة من قوة هذا الظرف الخاص.

وبعبارة مبسطة ، يعني هذا ببساطة أن كل حرف فردي في سلسلة يمكن تشغيله بسهولة كجزء من ترتيب متسلسل للعناصر ، تمامًا مثل المصفوفات في لغات البرمجة الأخرى.

لفهم كيفية عمل ذلك ، يمكن أن يوفر مراجعة example02 نظرة عامة جيدة.

Example02

### example02 -------------------
## start (with positive integers)
print 'coup_ate_grouping'[0]  ## => 'c'
print 'coup_ate_grouping'[1]  ## => 'o' 
print 'coup_ate_grouping'[2]  ## => 'u' 

## start (with negative integers)
print 'coup_ate_grouping'[-1]  ## => 'g'
print 'coup_ate_grouping'[-2]  ## => 'n' 
print 'coup_ate_grouping'[-3]  ## => 'i' 

## start:end 
print 'coup_ate_grouping'[0:4]    ## => 'coup'    
print 'coup_ate_grouping'[4:8]    ## => '_ate'    
print 'coup_ate_grouping'[8:12]   ## => '_gro'    

## start:end 
print 'coup_ate_grouping'[-4:]    ## => 'ping' (counter-intuitive)
print 'coup_ate_grouping'[-4:-1]  ## => 'pin'
print 'coup_ate_grouping'[-4:-2]  ## => 'pi'
print 'coup_ate_grouping'[-4:-3]  ## => 'p'
print 'coup_ate_grouping'[-4:-4]  ## => ''
print 'coup_ate_grouping'[0:-1]   ## => 'coup_ate_groupin'
print 'coup_ate_grouping'[0:]     ## => 'coup_ate_grouping' (counter-intuitive)

## start:end:step (or start:end:stride)
print 'coup_ate_grouping'[-1::1]  ## => 'g'   
print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc'

## combinations
print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc'

استنتاج

قد يكون العبء المعرفي المرتبط بفهم كيفية عمل تدوين الشريحة في python أكثر من اللازم لبعض المطورين والمطورين الذين لا يرغبون في استثمار الكثير من الوقت في تعلم اللغة.

ومع ذلك ، بمجرد فهم المبادئ الأساسية ، يمكن أن تكون قوة هذا النهج على أساليب التلاعب بالسلسلة الثابتة مواتية للغاية.

بالنسبة لأولئك الذين يفكرون بطريقة أخرى ، هناك طرق بديلة ، مثل وظائف lambda ، ومكررات ، أو إعلانات دالة لمرة واحدة بسيطة.

إذا رغبت في ذلك ، فيمكن لمطوّر البرامج تنفيذ طريقة string.reverse () الخاصة به ، إلا أنه من الجيد فهم الأساس المنطقي وراء هذا الجانب من python.

أنظر أيضا


s = 'Hello world'

الصورة [:: - 1]

في المثال المذكور أعلاه ، أو s المتغير هو عقد سلسلة تحتوي على سلسلة Hello World ، وفي الخطوة الثانية ، انقر فوق عكس سلسلة Hello world من خلال البدء من كل شيء إلى كل شيء في ترتيب خطوة معكوس -1.


بالتأكيد ، في بيثون يمكنك أن تفعل أشياء رائعة للغاية من سطر واحد. :)
هنا حل بسيط ، كل مستدير يمكن أن يعمل في أي لغة برمجة.

def reverse_string(phrase):
    reversed = ""
    length = len(phrase)
    for i in range(length):
        reversed += phrase[length-1-i]
    return reversed

phrase = raw_input("Provide a string: ")
print reverse_string(phrase)

طريقة أقل محيرة للنظر إليها ستكون:

string = 'happy'
print(string)

'السعيدة'

string_reversed = string[-1::-1]
print(string_reversed)

"ايباة"

في اللغة الإنجليزية [-1 :: - 1] كما يلي:

"بدء من -1 ، انتقل على طول الطريق ، مع اتخاذ خطوات -1"


طريقة متكررة:

def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])

مثال:

print(reverse("Hello!"))    #!olleH

كل الحلول المذكورة أعلاه مثالية ولكن إذا كنا نحاول عكس سلسلة باستخدام حلقة في python سيصبح الأمر صعبًا إلى حد ما ، لذلك هنا يمكننا عكس سلسلة باستخدام الحلقة

string ="hello,world"
for i in range(-1,-len(string)-1,-1):
    print (string[i],end=(" ")) 

آمل أن يكون هذا مفيدًا لشخص ما.


كيف حول:

>>> 'hello world'[::-1]
'dlrow olleh'

هذا هو امتداد شريحة شريحة . إنه يعمل عن طريق العمل [begin:end:step] - عن طريق ترك البداية والنهاية وتحديد خطوة -1 ، فإنه يعكس سلسلة.


هنا هو واحد لا يتوهم:

def reverse(text):
    r_text = ''
    index = len(text) - 1

    while index >= 0:
        r_text += text[index] #string canbe concatenated
        index -= 1

    return r_text

print reverse("hello, world!")

هنا واحد بدون [::-1] أو reversed (لأغراض التعلم):

def reverse(text):
    new_string = []
    n = len(text)
    while (n > 0):
        new_string.append(text[n-1])
        n -= 1
    return ''.join(new_string)
print reverse("abcd")

يمكنك استخدام += لسَلسَلة السلاسل إلا أن join() أسرع.


def reverse(input):
    return reduce(lambda x,y : y+x, input)

s = 'hello'
ln = len(s)
i = 1
while True:
    rev = s[ln-i]
    print rev,
    i = i + 1
    if i == ln + 1 :
        break

انتاج :

o l l e h




string