Pythonic way to unpack a inner string and process it - python

I want to split a inner string in order to get every item, the string is into a [()] structure,the object to process could be something like:
[(u'|name1|name2|name3|123|124|065|',)]
or
[(u'|name1|',)]
or
[(u'')]
or even
false
To get the items from the string I only need:
mystring.split('|')
But I think that my final approach is ugly and error-prone:
mylist[0][0].split('|')
How can I get a items list in a clean and pythonic way?

I think your approach is correct.
But what about the first and last elements of split('|') result?. They are empty because your strings starts and ends with a '|'.
You could use list comprehension.
[name for name in mylist[0][0].split('|') if name]
Or striping the string before:
mylist[0][0].strip('|').split('|')

Just do some previous checking.
If the string can be nested at not constant depth, just wrap the extraction in a loop until it is instance of basestring.
def split(container):
if not container:
return []
return container[0][0].split('|')

I agree that you're getting the best you can, but if you just want a different (equivalent) way of doing it,
from operator import itemgetter
f = itemgetter(0)
f(f(mylist)).split('|')

Related

Is there a way to use filter() to return a modified value with a lambda?

I was trying to check for palindromes and wanted to eliminate non alphanumeric characters. I can use filter for this like so:
filteredChars = filter(lambda ch: ch.isalnum(), s)
However, I also need to compare with the same case so I would really like to get is ch.lower so I tried this.
filteredChars = filter(lambda ch.lower() : ch.isalnum(), s)
but I got an error.
Is it possible to write a lambda to do this without a list comprehension or a user defined function?
I can already get my answer with:
filteredChars = [ch.lower() for ch in s if ch.isalnum()]
However, this DigitalOcean filter() tutorial says that list comprehensions use up more space
... a list comprehension will make a new list, which will increase the run time for that processing. This means that after our list comprehension has completed its expression, we’ll have two lists in memory. However, filter() will make a simple object that holds a reference to the original list, the provided function, and an index of where to go in the original list, which will take up less memory
Does filter only hold references to the filtered values in the original sequence? When I think of this though, I conclude (maybe not correctly) that if I have to lower the cases, then I would actually need a new list with the modified characters hence, filter can't be used for this task at all.
First of all, the reason this didn't work is simply syntax. An argument for a lambda can't pass through operations and is simply a declaration, just like regular functions.
Next, you can't really modify the return value as filter needs the function to return a boolean - which values to pass or filter. It can't modify the actual values. So if you want to use filter you need to "normalize" its input to be lowercase:
filteredChars = filter(lambda ch: ch.isalnum(), s.lower())
Alternatively, you can convert the exact list-comprehension you used to a generator expression, as simply as changing the brackets [...] to parenthesis (...):
filteredChars = (ch.lower() for ch in s if ch.isalnum())
Lastly, as this can be confusing, you can also create a generator and loop over that:
def filter_chars(s):
for ch in s:
if ch.isalnum():
yield ch.lower()
And now going in line with the previous methods you can do:
filteredChars = filter_chars(s)
Or as you are probably going to iterate over filteredChars anyway, just do directly:
for ch in filter_chars(s):
# do stuff
filter does
Construct an iterator from those elements of iterable for which
function returns true.(...)
as you wish to select and alter elements, this is not task for filter alone but rather composition of filter and map in this particular case this might be written following way
s = "Xy1!"
filteredChars = map(str.lower,filter(str.isalnum,s))
for c in filteredChars:
print(c)
gives output
x
y
1
filter and map are members of trinity, where third one is reduce (inside python2) xor functools.reduce (inside python3).
One way to do that is applying filter(), then joining the string, then applying lower():
"".join(filter(lambda ch: ch.isalnum(), s)).lower()
Another is using map() and a ternary operator:
"".join(map(lambda ch: ch.lower() if ch.isalnum() else "", s))

Python convert list of tuples into single tuple

Is there a way to convert a list of tuples into a single tuple? I have received a list of tuples from cursor.fetchall() but would like to make this into a single tuple:
curr_table_columns = cursor.fetchall()
For example:
[(u'w_id',), (u'w_name',), (u'w_street',)]
becomes
[(u'w_id', u'w_name', u'w_street')]
With itertools.chain, it's trivial. from itertools import chain and you can do either:
[tuple(chain.from_iterable(curr_table_columns))]
or:
[tuple(chain(*curr_table_columns))]
The former is preferred for long or unbounded iterable inputs (though don't wrap in tuple for unbounded!); for a small input (particularly one that's already a list or tuple), the latter is slightly slower, but fine. Either one is going to be significantly faster than a genexpr and indexing for inputs of any size at all.
Try this:
a=[(u'w_id',), (u'w_name',), (u'w_street',)]
print [tuple([i[0] for i in a])]
Output:
[(u'w_id', u'w_name', u'w_street')]
Not efficient*, but it is simple:
>>> ts = [(u'w_id',), (u'w_name',), (u'w_street',)]
>>> sum(ts, ())
('w_id', 'w_name', 'w_street')
So, just wrap it in a list if you must:
>>> result = [sum(ts, ())]
>>> result
[('w_id', 'w_name', 'w_street')]
*Warning: scales quadratically. Some might be inclined to let is slide for joining some column names into a single container. Definitely don't try to process millions of tuples this way.
Use itertools solution for linear time.
This function can convert listWidgets item into single tuple and also convert multiple element of tuple into single element tuple : Used for Sqlite3 and data query from listwidgets.
def tuple_converter(self,item):
target = ''
for i in item:
target += i + " "
target = target.rstrip()
target = tuple(target.split(","))
return target
#syntax name = tuple_converter(tuple((item).split()))
'''

How to build a string from key/value pairs in dict

If I have a dictionary such as:
clues = {'w':'e','r':'t'}
How do I get the first of each letter in the two to join together in a string, it is something like...
for clue in clues:
clue = ''.join(
However I don't know how to get them into a string from this...
Edit:
You can use a list comprehension for that:
>>> clues = {'w':'e','r':'t'}
>>> [''.join(x) for x in (clues, clues.values())]
['wr', 'et']
>>>
how would you get the first of each letter in the two to join together
in a string
I think you are talking about the dictionary's keys. If so, then you can use str.join:
>>> clues = {'w':'e','r':'t'}
>>> ''.join(clues)
'wr'
>>>
Also, iterating over a dictionary (which is what str.join is doing) will yield its keys. Thus, there is no need to do:
''.join(clues.keys())
Finally, #DSM made a good point. Dictionaries are naturally unordered in Python. Meaning, you could get rw just as easily as you get wr.
If you want a dictionary with guarunteed order, check out collections.OrderedDict.
And if you want all the keys joined into a string, try this:
''.join(clues.keys())
It's not entirely clear what your question is, but if you want to join the key and value together, storing that result into a new set, this would be the solution:
>>> {''.join(key_value) for key_value in clues.items()}
set(['rt', 'we'])
Written long hand for clarity:
out_set = set()
for key_value in clues.items():
key_value_joined = ''.join(key_value)
out_set.add(key_value_joined)
This should do the trick:
''.join(clues.keys())

Replace whitespaces with dashes for each item in a list -python

Is there a way of simplifying this loop where i replaces whitespace with dashes for each item in a list?
for item in a_list:
alist[alist.index(item)] = '-'.join(item.split(" "))
or is this better?
for item in a_list:
alist[alist.index(item)] = item.replace(" ", "-")
NOTE: The above solution only updates the 1st occurrence in this list, as David suggested, use list comprehension to do the above task.
I have a list of words and some have dashes while some doesn't. The items in a_list looks like this:
this-item has a-dash
this has dashes
this should-have-more dashes
this foo
doesnt bar
foo
bar
The output should look like this, where all items in list should have dashes instead of whitespace:
this-item-has-a-dash
this-has-dashes
this-should-have-more-dashes
this-foo
doesnt-bar
foo
bar
Use a list comprehension:
a_list = [e.replace(" ", "-") for e in a_list]
When you find yourself using the index method, you've probably done something wrong. (Not always, but often enough that you should think about it.)
In this case, you're iterating a list in order, and you want to know the index of the current element. Looking it up repeatedly is slow (it makes an O(N) algorithm O(N^3))—but, more importantly, it's fragile. For example, if you have two identical items, index will never find the second one.
This is exactly what enumerate was created for. So, do this:
for i, item in enumerate(a_list):
alist[i] = '-'.join(item.split(" "))
Meanwhile, you could replace the loop with a list comprehension:
a_list = ['-'.join(item.split(" ")) for item in a_list]
This could be slower or use more memory (because you're copying the list rather than modifying it in-place), but that almost certainly doesn't matter (it certainly won't be as slow as your original code), and immutable algorithms are simpler and easier to reason about—and more flexible; you can call this version with a tuple, or an arbitrary iterable, not just a list.
As another improvement, do you really need to split and then join, or can you just use replace?
a_list = [item.replace(" ", "-") for item in a_list]
You could use regular expressions instead, which might be better for performance or readability in some similar cases—but I think in this case it would actually be worse. So, once you get here, you're done.

how can i append in reverse? python

.append
Function adds elements to the list.
How can I add elements to the list? In reverse? So that index zero is new value, and the old values move up in index?
What append does
[a,b,c,d,e]
what I would like.
[e,d,c,b,a]
Thank you very much.
Suppose you have a list a, a = [1, 2, 3]
Now suppose you wonder what kinds of things you can do to that list:
dir(a)
Hmmmm... wonder what this insert thingy does...
help(a.insert)
Insert object before index, you say? Why, that sounds a lot like what I want to do! If I want to insert something at the beginning of the list, that would be before index 0. What object do I want to insert? Let's try 7...
a.insert(0, 7)
print a
Well, look at that 7 right at the front of the list!
TL;DR: dir() will let you see what's available, help() will show you how it works, and then you can play around with it and see what it does, or Google up some documentation since you now know what the feature you want is called.
It would be more efficient to use a deque(double-ended queue) for this. Inserting at index 0 is extremely costly in lists since each element must be shifted over which requires O(N) running time, in a deque the same operation is O(1).
>>> from collections import deque
>>> x = deque()
>>> x.appendleft('a')
>>> x.appendleft('b')
>>> x
deque(['b', 'a'])
Use somelist.insert(0, item) to place item at the beginning of somelist, shifting all other elements down. Note that for large lists this is a very expensive operation. Consider using deque instead if you will be adding items to or removing items from both ends of the sequence.
Using Python's list insert command with 0 for the position value will insert the value at the head of the list, thus inserting in reverse order:
your_list.insert(0, new_item)
You can do
your_list=['New item!!']+your_list
But the insert method works as well.
lst=["a","b","c","d","e","f"]
lst_rev=[]
lst_rev.append(lst[::-1])
print(lst_rev)
Here's an example of how to add elements in a list in reverse order:
liste1 = [1,2,3,4,5]
liste2 = list()
for i in liste1:
liste2.insert(0,i)
Use the following (assuming x is what you want to prepend):
your_list = [x] + your_list
or:
your_list.insert(0, x)

Categories

Resources