Suppose I want to change 'abc' to 'bac' in Python. What would be the best way to do it?
I am thinking of the following
tmp = list('abc')
tmp[0],tmp[1] = tmp[1],tmp[0]
result = ''.join(tmp)
You are never editing a string "in place", strings are immutable.
You could do it with a list but that is wasting code and memory.
Why not just do:
x = 'abc'
result = x[1] + x[0] + x[2:]
or (personal fav)
import re
re.sub('(.)(.)', r'\2\1','abc')
This might be cheating, but if you really want to edit in place, and are using 2.6 or older, then use MutableString(this was deprecated in 3.0).
from UserString import MutableString
x = MutableString('abc')
x[1], x[0] = x[0], x[1]
>>>>'bac'
With that being said, solutions are generally not as simple as 'abc' = 'bac' You might want to give us more details on how you need to split up your string. Is it always just swapping first digits?
You cannot modify strings in place, they are immutable. If you want to modify a list in place, you can do it like in your example, or you could use slice assignment if the elements you want to replace can be accessed with a slice:
tmp = list('abc')
tmp[0:2] = tmp[1::-1] # replace tmp[0:2] with tmp[1::-1], which is ['b', 'a']
result = ''.join(tmp)
Related
i have list of strings
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
and i have prefix string :
/root
is there any pythonic way to add the prefix string to each element in the list
so the end result will look like this:
lst = ["/root/foo/dir/c-.*.txt","/root/foo/dir2/d-.*.svc","/root/foo/dir3/es-.*.info"]
if it can be done without iterating and creating new list ...
used:
List Comprehensions
List comprehensions provide a concise way to create lists. Common
applications are to make new lists where each element is the result of
some operations applied to each member of another sequence or
iterable, or to create a subsequence of those elements that satisfy a
certain condition.
F=Strings
F-strings provide a way to embed expressions inside string literals,
using a minimal syntax. It should be noted that an f-string is really
an expression evaluated at run time, not a constant value. In Python
source code, an f-string is a literal string, prefixed with 'f', which
contains expressions inside braces. The expressions are replaced with
their values.
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix = '/root'
lst =[ f'{prefix}{path}' for path in lst]
print(lst)
I am not sure of pythonic, but this will be also on possible way
list(map(lambda x: '/root' + x, lst))
Here there is comparison between list comp and map List comprehension vs map
Also thanks to #chris-rands learnt one more way without lambda
list(map('/root'.__add__, lst))
Use list comprehensions and string concatenation:
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
print(['/root' + p for p in lst])
# ['/root/foo/dir/c-.*.txt', '/root/foo/dir2/d-.*.svc', '/root/foo/dir3/es-.*.info']
Just simply write:
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix="/root"
res = [prefix + x for x in lst]
print(res)
A simple list comprehension -
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix = '/root'
print([prefix + string for string in lst]) # You can give it a variable if you want
I have a dictionary similar to this
x ={'1': [['a','b'],['ac','d']], '2' : [['p','qa'],['r','s']]}
And I would like to access the individual strings i.e. a,b etc , compare if it has "a" in it, delete those.
The main question is - how do I access the strings? How do I change it?
I tried using nested loops, but was unable to change, as I guess assignment stmts do not work that way.
Any idea how to proceed with such situation?
Edit : The naive approach I used -
for item in x:
for ele in x[item]:
for i in ele:
i = #assign new value here using regex comparison
But when I try to print x after this, it stays same.
Obviously. assignment statements do not work this way. Any idea about how should I access the elements to change it?
>>> x ={'1': [['a','b'],['ac','d']], '2' : [['p','qa'],['r','s']]}
>>> for key in x:
... for n, item in enumerate(x[key]):
... x[key][n] = list(filter(lambda l: 'a' not in l, x[key][n]))
...
>>> x
{'2': [['p'], ['r', 's']], '1': [['b'], ['d']]}
In your example,
for item in x:
for ele in x[item]:
for i in ele:
i = #assign new value here using regex comparison
i is a copy of the string in ele, so assigning to it has no effect on the original. You need to modify the list ele. Possibly, ele[ele.index(i)] = #whatever. Note, however, that this will not work correctly if you have identical values in the list. It will only change the first one.
Not sure what you're actually trying to do, but it may be easier to use a list comprehension, at least for the innermost list. This will allow you to change each element of the innermost list. Perhaps,
for item in x.values():
for ele in item:
ele[:] = [#whatever for i in ele]
where ele[:] is needed to change the original inner list (just ele won't work), and I used the more Pythonic x.values() when we actually wanted the values, not the keys.
I am trying to check if a string object is in a list. Simply written as:
if str in list:
The problem I am facing is that this list, is not a list of strings, but a list of tables. I understand that nothing is going to happen if I do this comparison directly. What I would like to do is access an attribute of each of these tables called 'Name'.
I could create a new list, and do my comparison against that:
newList = []
for i in list:
newList.append(i.Name)
But as I am still a newbie, I am curious about Lambda's and wondered if it would be possible to implement that instead?
something like (... but probably nothing like):
if str in list (lambda x: x.Name):
You can write
if str in [x.Name for x in list]
Or more lazily,
if str in (x.Name for x in list)
In the latter (with parens) it builds a generator, while in the former (with brackets), it builds first the full list.
Lambdas pretty much doesn't needed here. You can just check it directly:
for table in my_list:
if string in table.Name:
#do stuff
Or using list comprehension, if you want it that way:
if string in [table.Name for table in my_list]:
#do interesting stuff
More efficiently, as #Tim suggested, use a generator expression:
if string in (table.Name for table in my_list):
But if you insist in using lambdas:
names = map(lambda table: table.Name, my_list)
if string in names:
#do amazing stuff!
Here's a little demo:
>>> class test():
def __init__(self, name):
self.Name = name
>>> my_list = [test(n) for n in name]
>>> l = list(map(lambda table: table.Name, my_list)) #converted to list, it's printable.
>>> l
['a', 'b', 'c']
Also, avoid using names of built in functions such as str, list for variable names. It will override them!
Hope this helps!
I guess you're looking for any:
if any(x.Name == s for x in lst):
...
If the list is not large and you need these names somewhere else, you can create a list or a set of names:
names = {x.Name for x in lst}
if s in names:
....
The lambda you wrote is already in python, and called attrgetter (in module operator):
names = map(attrgetter('Name'), lst)
Note that comprehensions are usually preferred to that.
you can use filter
>>> foo = ["foo","bar","f","b"]
>>> list(filter( lambda x:"f" in x,foo))
['foo', 'f']
update
i keep this answer because someone may come here for lambdas but for this problem #arbautjc 's answer is better.
Assume you have a list such as
x = [('Edgar',), ('Robert',)]
What would be the most efficient way to get to just the strings 'Edgar' and 'Robert'?
Don't really want x[0][0], for example.
Easy solution, and the fastest in most cases.
[item[0] for item in x]
#or
[item for (item,) in x]
Alternatively if you need a functional interface to index access (but slightly slower):
from operator import itemgetter
zero_index = itemgetter(0)
print map(zero_index, x)
Finally, if your sequence is too small to fit in memory, you can do this iteratively. This is much slower on collections but uses only one item's worth of memory.
from itertools import chain
x = [('Edgar',), ('Robert',)]
# list is to materialize the entire sequence.
# Normally you would use this in a for loop with no `list()` call.
print list(chain.from_iterable(x))
But if all you are going to do is iterate anyway, you can also just use tuple unpacking:
for (item,) in x:
myfunc(item)
This is pretty straightforward with a list comprehension:
x = [('Edgar',), ('Robert',)]
y = [s for t in x for s in t]
This does the same thing as list(itertools.chain.from_iterable(x)) and is equivalent in behavior to the following code:
y = []
for t in x:
for s in t:
y.append(s)
I need to send this string to another function.
If your intention is just to call a function for each string in the list, then there's no need to build a new list, just do...
def my_function(s):
# do the thing with 's'
x = [('Edgar',), ('Robert',)]
for (item,) in x:
my_function(item)
...or if you're prepared to sacrifice readability for performance, I suspect it's quickest to do...
def my_function(t):
s = t[0]
# do the thing with 's'
return None
x = [('Edgar',), ('Robert',)]
filter(my_function, x)
Both map() and filter() will do the iteration in C, rather than Python bytecode, but map() will need to build a list of values the same length of the input list, whereas filter() will only build an empty list, as long as my_function() returns a 'falsish' value.
Here is one way:
>>> [name for name, in x]
['Edgar', 'Robert']
Note the placement of the comma, which unpacks the tuple.
>>> from operator import itemgetter
>>> y = map(itemgetter(0), x)
>>> y
['Edgar', 'Robert']
>>> y[0]
'Edgar'
>>> y[1]
'Robert'
This code fails:
fCamel = 'F'
bCamel = 'B'
gap = ' '
k = ['F', ' ', 'B', 'F']
def solution(formation):
return ((formation.index(bCamel) > (len(formation) - 1 - (formation.reverse()).index(fCamel))))
solution(k)
I get an exception that says AttributeError: 'NoneType' object has no attribute 'index'.
I know that the problem is that list.reverse() returns None, modifying the list in-place. I want to use .index on the reversed list. Is there a way I can avoid using a separate statement to reverse the list before indexing into it? How?
You can use slicing to return the reversed list:
l[::-1]
You can use reversed(formation) to return a reverse iterator of formation. When you call formation.reverse() it does an in place reversal of the list and returns None.
EDIT:
I see what you are trying to do now, in my opinion it's easier to just do this with a list comprehension:
def solution(formation):
return len([k for k in formation[formation.index(bCamel)+1:] if k == fCamel]) == 0
This basically looks at all the elements after the first bCamel and collects all the elements that have the value fCamel. If that list has a length == 0 you have a solution.
Here's a few examples:
>>> k = ['F','F','B','B','F']
>>> solution(k)
False
>>> k = ['F','F','B','B','B']
>>> solution(k)
True
>>> k = ['F','F','B','F','F','B','B']
>>> solution(k)
False
>>>
To build on GWW's answer, if you want this code to work as is you would just do list(reversed(formation)). If you really want to be able to use formation.reverse() instead, you would have to subclass list:
>>> class ReversableList(list):
... def reverse(self):
... return list(reversed(self))
...
>>> x = ReversableList([1,2,3])
>>> x.reverse()
[3, 2, 1]
Whether or not this is advisable is another question of course.
list.reverse reverses inplace. That is:
>>> l = [1, 2, 3]
>>> l.reverse()
>>> l
[3, 2, 1]
Please consult the Python documentation, things like these are laid out there. You can also try the 'help' built-in:
help(l.reverse) Help on built-in function reverse:
reverse(...)
L.reverse() -- reverse IN PLACE
I just came across this problem and wanted to clarify some things for users new to python coming from a javascript background.
In javascript, a.reverse() reverses in place and also returns the array when called.
Javascript:
var a = [2, 3 ,4]
console.log(a.reverse())
// outputs [4, 3, 2]
console.log(a)
// outputs [4, 3, 2]
In python, a.reverse() reverses in place, but does not return the array. This is what caused confusion for me.
In python:
a = [2, 3, 4]
a.reverse()
print(a)
# outputs [4, 3, 2]
# can't do print(a.reverse())
the following changes will be effective:
NumSet={1,2,3,4,5,6,7,8,9,10}
NumList = list(NumSet)
NumList.reverse()
print(NumList)
avoid using the assignment operator after the initial assignment as lists are mutable types.
Using = operator with a method..(eg NumList = NumSet.reverse()) will cause the method to overwrite list with a blank, thereby effectively clearing the list. That's why list becomes a NoneType.
Methods are functions and doesn't actually have its own value, thus the blank.
There are multiple approaches to the problem shown in the OP. A summary:
Use a different technique that gives you a reversed copy of the list, so that this expression can be used in place. The two main ways to do this are formation[::-1] and list(reversed(formation)) (see How to reverse a list?).
Analogous solutions exist to replace other list functionality, for example:
# mylist.append(1)
# mylist.index(1)
(mylist + [1]).index(1) # note that the value is wrapped in another list
# mylist.extend(anotherlist)
# mylist.index(1)
(mylist + anotherlist).index(1)
# mylist.sort()
# mylist.index(1)
sorted(mylist).index(1)
Bite the bullet and use a separate statement anyway. Simple is better than complex; good Python style often avoids long expressions like ((formation.index(bCamel) > (len(formation) - 1 - (formation.reverse()).index(fCamel)))) because it's hard to follow the logic. Keep in mind that since we are still using an in-place method, the original formation is still modified. This can be useful, but it often causes problems.
(Please do not use this in real code.) We can abuse conditional expressions to make the assignment happen as a side effect:
def solution(formation):
return formation.index(bCamel) > (
len(formation) - 1 - (formation.reverse() or formation).index(fCamel)
)
The idea is that since formation.reverse() will return None, which is falsey, so or is forced not to short-circuit, and will evaluate to formation - after the reversal has occurred as a side effect.
Other expressions can have the same net effect, e.g. [formation, formation.reverse()][0]. The idea is to write something that is an expression that includes the .reverse call, but evaluates to the original list object. We can be arbitrarily creative here - but again, Simple is better than complex. Please don't do these things.
Again, keep in mind that this will still modify the original list, which may impact on future calculations.
Rework the logic to avoid the need to reverse the list. The code tries to reverse the list, search in the reversed list for the index of the first match, and then subtract that result from len(formation) - 1 - the overall effect of this is to search for the index of the last match. Lists don't have a method for that, but strings do; and as it happens, all our elements are single-character strings. We could solve the problem more simply by representing the formation with a string:
def solution(formation):
return formation.index(bCamel) > formation.rindex(fCamel)
solution('F BF')
Alternately, we can conceive of the problem differently: "Is there a fCamel in the part of the list that follows the first bCamel?" The accepted answer shows using a list comprehension to iterate over "the part of the list that follows the first bCamel", making a list of all the fCamels there, and checking whether that list is non-empty. But we can do it much more simply:
# works with either the string or list input
def solution(formation):
return fCamel not in formation[formation.index(bCamel)+1:]
(There are even more clever ways to write this, such as Stefan's answer using iterators.)
Solutions like this are specific to the problem solved by the code, and don't answer the question in general. However, it is often possible to find similar solutions in other contexts.
Not super beautiful, but I did not find the equivalent in the precedent answers. If the speed or memory costs are low (the list is not very long or the operation not repeated a huge amount of times), this is pretty straight forward and even easier to read.
import copy
fCamel = 'F'
bCamel = 'B'
gap = ' '
k = ['F', ' ', 'B', 'F']
def solution(formation):
rev_formation = copy.copy(formation)
rev_formation.reverse()
return ((formation.index(bCamel) > (len(formation) - 1 -
(rev_formation).index(fCamel))))
Cheers
This doesn't provide a solution to the F _ B F pattern problem, but it does address the issue of python not returning a list when you use .reverse().
This is how I got around it:
chars = ['a', '-', 'c']
chars2 = [] + chars
chars2.reverse()
totalChars = chars + chars2
totalChars returns a-cc-a, which is what I wanted, AND chars2 is a list, not a pointer to chars. Hope this helps.
I don't know if this works for you, but this works for me:
list = [1,2,3]
print([list, list.reverse()][0])
The reason list.reverse() returns None is because the function doesn't return anything.
Using your code:
fCamel = 'F'
bCamel = 'B'
gap = ' '
k = ['F', ' ', 'B', 'F']
def solution(formation):
return ((formation.index(bCamel) > (len(formation) - 1 - ([formation, formation.reverse()][0]).index(fCamel))))
print(solution(k))
Hope this works for you!
ps. Honestly, I have no idea why this works. I stumbled on it accidentally.
Title question is already answered, but for what you were really after:
Basically, this function should return true if all the 'F's are on the left hand side of the first 'B'
That's the same as there's no 'B' followed by an 'F'. Nice way to check this is with an iterator:
def solution(formation):
it = iter(formation)
return not (bCamel in it and fCamel in it)
Some advantages:
Unlike every formation.index(...) solution it doesn't crash if the searched value isn't there.
Takes only O(1) extra space (unlike the solutions making a reversed copy of the list).
Touches every element at most once and stops as soon as possible. Even has O(1) time best case (even with millions of elements, if the list starts with ['B', 'F', then it stops right there).