1

Let's say for example that I have an array that represents a name and I want to use just the first letter of any part of a name that is not the first or the last part:

# Have
name = ["John", "Banana", "Doe"]

# Want
["John", "B", "Doe"]

Can I iterate through a subset of an array and change the variables inside it through the variable that references it like so?

for part in name[1:-1]:
    part = part[0]

The only solution I fould for this was to use list comprehention, but it was too hard to read:

name = [part if i in [0, len(name)-1] else part[0] for i, part in enumerate(name)]
1
  • 1
    comprehension can indeed be confounding. maybe bury it in an appropriately named function or use comments. you could also use numpy arrays of dtype object instead of lists for an alternate syntax, but additional dependencies is worse than keeping the confoundation. Commented Feb 15, 2022 at 13:15

4 Answers 4

4

v = v[0] reassigns the name v, that was previously bound to one of the list elements. This does not mutate the list, though.

You could fix your loop by iterating over an index range and explicitly reassign list elements.

for index in range(1, len(name) - 1):
    name[index] = name[index][0]

An easier to read list-comprehension solution would be:

name[1:-1] = [v[0] for v in name[1:-1]]

An equivalent solution without a list comprehension would be:

new_values = []

for v in name[1:-1]:
    new_value = v[0]
    new_values.append(new_value)

name[1:-1] = new_values

Bonus: repeating [1:-1] twice is not as clean as it could be. You could define a slice object to refer to the desired part of the list, e.g.

where = slice(1, -1)
name[where] = [v[0] for v in name[where]]
Sign up to request clarification or add additional context in comments.

3 Comments

What is the point of building up a list to assign to a slice when you can just do the individual assignments directly (as in your first solution)?
@ScottHunter educational reasons. OP is new to python and finds list comprehension hard to read.
I thought OP meant that comprehension in particular; yours was about as straight-forward as one could get.
1
start = 1
for i,v in enumerate(name[start:-1]):
    name[i+start] = v[0]

Or something slightly cleaner, using what I just learned about enumerate:

start = 1
for i,v in enumerate(name[start:-1],start):
    name[i] = v[0]

Comments

0

What about using enumerate with a set?

name = ["John", "Banana", "Doe"]

pos = {0, len(name)-1}

[w if i in pos else w[0] for i,w in enumerate(name)]

or with a classical loop (but without explicit check, the list should have more than 1 element):

out = name[:1]

for i in range(1, len(name)-1):
    out.append(name[i][0])

out.append(name[-1])

Comments

-1

You can do this

for i,v in enumerate(name[1:-1]):
   name[i] = v[0]

What you can't do while iterating over a list is changing the list size, but changing the content is allowed.

11 Comments

Not if you want OP's desired result.
What do you mean by that?
Did you actually try this & check the results?
That doesn't seem to work
Another problem with this approach is that the i starts at 0, but the iteration starts at 1. You would need to use name[i+1] to make it work.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.