python3-文字列で隣り合う同じ文字を削除したい-
解決済
回答 6
投稿
- 評価
- クリップ 1
- VIEW 2,327
文字列から隣り合う同じ文字を削除したい
例えば、"aabcacc"という文字列があった場合
「aa」と「cc」を削除して 「bca」となるようにしたい。
"abbac"であれば、「bb」を削除したら「aac」になり、「aa」を削除して最終的に「c」になる
今回はこの"abbac"を想定してコードを書いています。
s="abbac"
a=[]
b=[]
for i in range(len(s)):
a.append(s[i])
count = 0
while True:
for j in range(len(a)-1):
if a[j] == a[j+1]:
b.append(a[j])
b.append(a[j+1])
count += 1
if count == 0:
break
else:
count = 0
set_ab = set(a) - set(b)
list_ab = list(set_ab)
print(list_ab)
発生したエラー
ループから抜け出せない
なぜこのコードでは抜け出せられないのでしょうか・・・?文字列の文字が操作できないらしい?(あまり詳しくないので、ネット情報です)
文字列の文字の操作がreplace(s[0], "")のようにできないようだったので、
遠回りかもしれませんが、一度一文字ずつリストに格納して、delで削除することにしました。
質問したいこと
本当はリストを使うなんて遠回りしない方が良いのですが、リストを使わない場合、文字列の操作ができないという問題をどのように解決するのでしょうか?
なぜこのコードのbreakでループを終わらせられないのでしょうか?
*なにかアドバイスがあればどんなことでもいいのでお願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+4
正規表現を使うといいと思います。
import re
a="abcddefgghiiiij"
b=re.sub("([a-z])\\1", "", a)
print(b)
追記:
"aaa"とあったら、ペア(aa)を削除するようにしていますので、aが残ります!
という質問者の追加コメントに対応してみます。「否定先読み」を使い、「a-zのどれかが存在し、直後に同じ文字が続き、しかしその直後にその文字は続かない」を表現します。
import re
a="abcddefgghiiiij"
b=re.sub("([a-z])\\1(?!\\1)", "", a)
print(b)
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+3
リストを使わない場合
リストのようなコレクション的なものを作ってそれを加工するというのも別に悪くないのですが、「要素を一つ一つ流れ作業で料理する」という考え方が使えるような場合もかなり多いと思います。
functools.reduceを使った例を挙げてみます。reduceは要素を一つずつ取り出しては
... f(f(f(e0, e1), e2), e3) ...
というような関数の適用を繰り返して結果を求めてくれます。
fの第一引数は「前の要素までの簡約結果」で第二引数は「次の要素」です。本件の場合簡約結果を「連続した2つの文字を取り除いた結果」と考えると、以下のように書けます。
import functools
def drop_same(s, c):
return s[:-1] if s != '' and s[-1] == c else s + c
functools.reduce(drop_same, 'abbac', '') # 'c'
functools.reduce(drop_same, 'zabbaccz', '') # ''
Python 3.6.0
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
whileでループが回るたびに、内側のforが文字列を最初から最後までスキャンしてしまっています。今の入力では、連続する文字列があるので、forを回す間にcountが1になってしまい、決してbreakには到達できなくなっていますよ。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
自分で loop を回して処理する版と、正規表現を使う版を書いてみました。
replace.py
import re
def reduce_1(s):
a = []
b = []
for i in range(len(s)):
a.append(s[i])
while True:
j = 0
while j < len(a):
if j == len(a) - 1:
b.append(a[j])
elif (a[j] == a[j + 1]):
j += 1
else:
b.append(a[j])
j += 1
if len(a) == len(b):
break
a = b
b = []
return b
def reduce_2(s):
while True:
ss = re.sub("(.)\\1", "", s)
if s == ss:
return ss
s = ss
print(reduce_1("aabcacc"))
print(reduce_1("abbac"))
print(reduce_2("aabcacc"))
print(reduce_2("abbac"))
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
itertools.groupbyを使うのはいかがでしょうか。
from itertools import groupby
def has_serial_duplicated_chars(src_str):
return any(
ch1 == ch2 for ch1, ch2 in zip(src_str, src_str[1:])
)
def remove_serial_duplicated_chars(src_str):
while has_serial_duplicated_chars(src_str):
src_str = ''.join(
k for k, gen in groupby(src_str)
if sum(1 for _ in gen) % 2 == 1
)
return src_str
print(
remove_serial_duplicated_chars('abbac')
)
print(
remove_serial_duplicated_chars('abbbac')
)
実行結果 Wandbox
c
abac
過去の修正について
仕様の誤認が度重なり、二度にわたり大々的に回答を変更しています。
本来なら過去の回答に追記する形が良いのでしょうが、可読性を考慮し上書き修正いたしました。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
import re
def super_reduced_string(s):
for i in range(len(s)):
s=re.sub("([a-z])\\1", "", s)
if len(s) == 0:
print("Empty String")
break
print(s)
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
退会済みユーザー
2018/02/24 20:32
3文字連続してる場合はどうします?
n_oshiumi
2018/02/24 21:49
"aaa"とあったら、ペア(aa)を削除するようにしていますので、aが残ります!