1
votes

Remplacement du caractère d'une chaîne dans une liste

J'ai compris:

a.append(i[:i.find("o")] + " " +"o"+ i[i.find("o")+2:])

j'ai besoin du "o" pour en déplacer un vers la droite

state = (
    "#####   ",
    "###    #",
    "##   o##",
    "   #####"
)

à

def move(state, direction):
   
    for indx,i in enumerate(state):
        if "o" in i:
            line_indx= indx
            
    string_indx = state[line_indx].find("o")
    print(line_indx,string_indx)
    
    a=[]
    if direction.lower() == "rechts" and state[line_indx][string_indx+1] == " ":
        print("that would work")
        for i in state:
            if "o" not in i:
                a.append(i)
            elif "o" in i:
                a.append(i[:i.find("o")] + " o" + i[i.find("o")+1:])

le fait est qu'il doit être vraiment robuste pour les cas de pointe comme:

"o ##"

J'ai codé comme ça mais ça ne fonctionnera pas comme ça ...

"##   o##"

Je dois me débarrasser de ce truc de tranchage mais je ne sais pas comment ...

Merci d'avance!!

EDIT: la sortie devrait ressembler à ceci

"##  o ##"

E2:

state = (
    "#####   ",
    "###    #",
    "##  o ##",
    "   #####"
)

fonctionne mais il doit y avoir une meilleure solution ...


1 commentaires

Les chaînes et les tuples sont immuables en Python. Pouvez-vous plutôt représenter l'État sous forme de liste de listes? Ensuite, vous pouvez facilement attribuer des éléments individuels.


4 Réponses :


0
votes

si vous voulez que "## o #" soit converti en "## o #" voici le code. En supposant que "état" est une liste comme vous l'avez mentionné "liste" dans la question

for indx,i in enumerate(state):
    if "o " in i:
            line_indx= indx
            state[indx]=i.replace("o ","o")
print(state)


2 commentaires

state est clairement un tuple. Comme les tuples sont immuables, votre solution ne fonctionnera pas. D'où avez-vous également obtenu la variable l ?


je l'ai édité. La liste était mentionnée dans la question



2
votes

J'utiliserais re module pour la manière suivante:

('#####   ', '###    #', '##   o##', '   #####')

Production:

import re
state = (
    "#####   ",
    "###    #",
    "##  o ##",
    "   #####"
)
new_state = tuple(re.sub(r"(o)(\s)", r"\2\1", i) for i in state)
print(new_state)

Notez que cela permutera chaque o avec un espace à sa droite, pour chaque o qui a un espace à sa droite. Explication: J'ai utilisé ce que l'on appelle des groupes de capture et des références pour eux.


2 commentaires

fou, merci beaucoup !! pouvez-vous m'expliquer les choses à l'intérieur du re.sub () ou m'envoyer un lien avec des explications? Je dois le faire pour différents cas également (déplacement vers la gauche par exemple)


@Orsons: Je suggère d'abord de lire la documentation re.sub , puis d'utiliser regex101 pour comprendre ce modèle particulier



2
votes

Je dirais que le moyen le plus simple de résoudre ce problème est de vérifier pour chaque ligne si elle contient un «o». Si c'est le cas, vous voulez que la ligne soit tout avant le 'o' ( line[0:idx] ), alors le 'o' précédé d'un espace ( " o" ) et puis tout après le 'o', en tenant compte du espace nouvellement ajouté ( line[idx + 2:] ).

...
if 'o' in line:
    idx = line.find('o')
    line = left(line, idx)
...

Cela donnera la sortie:

def left(line, idx):
    return line[0:idx - 1] + "o " + line[idx + 1:]

def right(line, idx):
    return line[0:idx] + " o" + line[idx + 2:]

ÉDITER

Je vois dans un commentaire que vous voulez également pouvoir vous déplacer vers la gauche, etc. Dans ce cas, vous pouvez remplacer le contenu de l'instruction if par un appel de fonction qui traite la ligne en conséquence, c'est-à-dire:

('#####   ', '###    #', '##   o##', '   #####')

Et puis à l'intérieur de la boucle:

state = (
    "#####   ",
    "###    #",
    "##  o ##",
    "   #####"
)
newstate = []

for line in state:
    if 'o' in line:
        idx = line.find('o')
        line = line[0:idx] + " o" + line[idx + 2:]
    newstate.append(line)

state = tuple(newstate)
print(state)


0 commentaires

1
votes

En supposant que vous vouliez pouvoir vous déplacer dans les quatre directions et pas seulement vers la droite. À mon avis, il est plus facile de travailler avec des séquences mutables pour de tels types de problèmes (comme Thomas l'a suggéré). Ie utilise une List imbriquée comme état au lieu du tuple immuable de str s. Si vous ne parvenez pas à modifier la signature de la fonction, vous pouvez utiliser des casts de type comme ceci:

def test_move_right():
    state = (
        "#####   ",
        "###    #",
        "##  o ##",
        "   #####"
    )

    expected_state = (
        "#####   ",
        "###    #",
        "##   o##",
        "   #####"
    )

    new_state = move(state, Direction.right)
    assert new_state == expected_state


def test_move_right_blocked():
    state = (
        "#####   ",
        "###    #",
        "##   o##",
        "   #####"
    )

    with pytest.raises(AssertionError):
        move(state, Direction.right)


def test_move_right_out():
    state = (
        "#####  o",
        "###    #",
        "##    ##",
        "   #####"
    )

    with pytest.raises(AssertionError):
        move(state, Direction.right)

Testez les hypothèses suivantes:

  • Se déplacer à droite dans un espace vide fonctionne ( ).
  • Vous ne devriez pas pouvoir sortir du terrain par la droite.
  • Vous ne devriez pas pouvoir vous déplacer directement dans un # .

Vous devriez également vérifier les autres cas extrêmes.

import typing as t
from enum import Enum

State = t.Tuple[str, ...]
Position = t.Tuple[int, int]


class Direction(str, Enum):
    up = "up"
    down = "down"
    left = "left"
    right = "right"


def get_position(state: State) -> Position:
    o_indices = [(x, y) for x, row in enumerate(state) for y, item in enumerate(row) if item == "o"]
    assert len(o_indices) == 1, "There must be exactly one o."
    return o_indices[0]


def move(state: State, direction: Direction) -> State:
    x, y = old_x, old_y = get_position(state)

    if direction == "down":
        x += 1
    elif direction == "up":
        x -= 1
    elif direction == "right":
        y += 1
    elif direction == "left":
        y -= 1

    # Assert validity of move:
    assert 0 <= x < len(state), "Trying to move out of field vertically."
    assert 0 <= y < len(state[0]), "Trying to move out of field horizontally."
    assert state[x][y] != "#", "Trying to move into fence."

    # This would be easier with a MutableSequence, i.e. if state was a nested List
    new_state = list(list(row) for row in state)
    new_state[x][y] = "o"
    new_state[old_x][old_y] = " "

    return tuple("".join(row) for row in new_state)


1 commentaires

Merci pour votre réponse détaillée! Cela m'a beaucoup aidé, j'ai juste oublié de voter ... désolé