I have two strings types; each type can have one of the following exemplary forms:
str = ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
or
str = ((0, 1, 2), (3, 4, 5, 6, 7), (8, 9))
The number of substrings within parentheses in the second form can range from 1 to any number.
I need a) to be able to detect the presence of each form, and b) if the string has the second form I need to extract each of the substrings within each of the inner parenthesis.
I have a basic understanding of regular expressions but I can't see how this should be handled.
If these are the only two options you can use:
if type(str[0]) == int:
print 'TYPE1'
else if type(str[0]) == tuple:
print 'TYPE2'
else:
print 'unknown'
and for your second question, in case you're in form 2, use:
list(sum(str, ()))
to flatten the tuple, this way you can access every element individually.
If you want to access the tuples as whole, you can use:
for element in str:
#element is an inner tuple
for inner_element in element:
#inner_element is an integer within the tuple
print inner_element
Hope this helps
Related
I am trying to remove the floating point in the tuple using a lambda function.
I am slicing the tuple and converting the last element in the tuple to int and concatenating it.
xyz = list((filter(lambda x : x[2].is_integer(), sides_triplet )))
print(xyz)
xy = list(map(lambda tup : tup[:2] + (int(tup[2]),), xyz))
print(xy)
Output:
[(3, 4, 5.0), (6, 8, 10.0)]
[(3, 4, 5), (6, 8, 10)]
The code works perfectly fine but my question is on the line:
xy = list(map(lambda tup : tup[:2] + (int(tup[2]),), xyz))
Need explanation as to why we use comma and then close the braces after int.
Instead if I use the line below, it throws an error, why is that?
xy = list(map(lambda tup : tup[:2] + (int(tup[2])), xyz))
Output:
xy = list(map(lambda tup : tup[:2] + (int(tup[2])), xyz))
TypeError: can only concatenate tuple (not "int") to tuple
see below
data = [(3, 4, 5.0), (6, 8, 10.0)]
new_data = [(x[0], x[1], int(x[2])) for x in data]
print(new_data)
output
[(3, 4, 5), (6, 8, 10)]
The main thing to understand and in answer toyour question about why the comma is needed before the closing bracket and why it fails when you dont include the comma.
When you want to create a tuple in python which has a single value you need to end it with a comma to tell python this is a tuple with a single value. Other wise python considers it just as an expression and will evaluate it and return the value of that expression (in this case an int)
first = (int("1"))
second = (int("1"),)
print(f"type={type(first)}, value={first}")
print(f"type={type(second)}, value={second}")
OUTPUT
type=<class 'int'>, value=1
type=<class 'tuple'>, value=(1,)
It doesnt work in your example without the comma becuase you are trying to concat the first value (a tuple) to the second value an int, and python wont allow that. By adding in the comma you create a tuple with a single value which is an int. These can then be concat together as both are tuples.
I have this input, where each value has a range of 200:
d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}
And I am looking for this expected order:
{'400-600': 1, '600-800': 3, '1000-1200': 5, '1800-2000': 3, '2600-2800': 1}
Already tried something like this, but the order is just wrong:
import collections
od = collections.OrderedDict(sorted(d.items()))
print od
You can split the key into parts at '-' and use the first part as integer value to sort it. The second part is irrelevant for ordering because of the nature of your key-values (when converted to integer):
d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}
import collections
od = collections.OrderedDict(sorted(d.items(),key =lambda x: int(x[0].split("-")[0])))
print od
Output:
OrderedDict([('400-600', 1), ('600-800', 3), ('1000-1200', 5),
('1800-2000', 3), ('2600-2800', 1)])
Doku:
sorted(iterable,key)
Related:
How to sort a list of objects based on an attribute of the objects? for more "sort by key" examples
Are dictionaries ordered in Python 3.6+? .. which lets you omit the OrderedDict from 3.7+ on (or 3.6 CPython)
If you want to order your dictionary by the first year first (and then by the second year if needed, which is unnecessary in the given example, but feels more natural), you need to convert to integers and set a custom key:
d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}
sorted(d.items(), key=lambda t: tuple(map(int, t[0].split("-"))))
# [('400-600', 1),
# ('600-800', 3),
# ('1000-1200', 5),
# ('1800-2000', 3),
# ('2600-2800', 1)]
The conversion to integers is needed because e.g. "1000" < "200", but 1000 > 200. This list can be passed to OrderedDict afterwards like in your code, if needed.
Help! What do I have to change so that it comes out like this?
[('Mavis', 3), ('Ethel', 1), ('Rick', 2), ('Joseph', 5), ('Louis', 4)]
Right now, with my code, it comes out like this.
bots_status = [(bot_one_info) + (bot_two_info) + (bot_three_info) + (bot_four_info) + (bot_five_info)]
[('Mavis', 3, 'Ethel', 1, 'Rick', 2, 'Joseph', 5, 'Louis', 4)]
Place commas instead of + signs between your bots.
If working with a variable amount of entries, initialize an array and add to it using append.
bots_status = []
for bot_info in bot_infos:
bots_status.append(bot_info)
Replace the plusses (+) by commas (,) to make this a list of tuples instead of a list of one concatenated tuple:
bots_status = [bot_one_info, bot_two_info, bot_three_info, bot_four_info, bot_five_info]
Since your bot_x_info variables already are tuples, you also don’t need to use parentheses around the names (those don’t do anything).
The problem with your code was that you were using + on the tuples. The add operator concatenates tuples to a single one:
>>> (1, 2) + (3, 4)
(1, 2, 3, 4)
That’s why you ended up with one giant tuple in your list.
What you wanted is have each tuple as a separate item in the list, so you just need to create a list from those. Just like you would do [1, 2, 3] to create a list with three items, using a comma to separate each item, you also do this with other values, e.g. tuples in your case.
Let's say:
bot_one_info = ('Mavis', 3)
bot_two_info = ('Mavi', 3)
If you use +
lis = [bot_one_info + bot_two_info]
print lis
#Output
[('Mavis', 3, 'Mavi', 3)]
But if you use ,
lis = [bot_one_info,bot_two_info]
print lis
#Output
[('Mavis', 3), ('Mavi', 3)]
You can use here , instead of +.
I have a list of lists with 4 elements in each of them.
LoL=[[1,1,1,1],[4,2,3,[1,3]],[4,5,3,[0,4]]]
The 4th elements can be a list of two parts like [0,4] in [4,5,3,[0,4]].
I need to use its elements as keys for a dictionary,
Pseudo code:
dic = { [1,1,1,1]:'a',[4,2,3,[1,3]]:'b',[4,5,3,[0,4]]:'c' }
so tried to change them to tuples.
It works for simple lists (like [1,1,1,1]), but for the ones containing another list (like [4,5,3,[0,4]]) it raises an error:
dic[tuple([1,1,1,1])]=['bla','blah']
print dic
{(1, 1, 1, 1): ['bla', 'blah']}
dic[tuple([4, 2, 3, [1, 3]])]=['blablah']
TypeError: unhashable type: 'list'
I need to reuse the keys as lists later. So trying to change elements of LoL to strings (e.g. using repr()) is not an option!
Edit:
I know why lists cannot be used as dictionary keys. Here they are not changed while in the dic. I just need some way to pass them to another module to extract them.
Just convert your nested lists to nested tuples. Here's a quick demo. It's not perfect, but it works.
#! /usr/bin/env python
LoL = [[1,1,1,1],[4,2,3,[1,3]],[4,5,3,[0,4]]]
def nested_list_to_tuple(nlist):
return tuple([nested_list_to_tuple(i) if isinstance(i, list) else i for i in nlist])
ToT = nested_list_to_tuple(LoL)
print ToT
output
((1, 1, 1, 1), (4, 2, 3, (1, 3)), (4, 5, 3, (0, 4)))
Just use tuples:
a = {}
a[(4, 2, 3, (1, 3))] = ['blablah']
print(a)
Output:
{(4, 2, 3, (1, 3)): ['blablah']}
I am new to python and have the following piece of test code featuring a nested loop and I'm getting some unexpected lists generated:
import pybel
import math
import openbabel
search = ["CCC","CCCC"]
matches = []
#n = 0
#b = 0
print search
for n in search:
print "n=",n
smarts = pybel.Smarts(n)
allmol = [mol for mol in pybel.readfile("sdf", "zincsdf2mols.sdf.txt")]
for b in allmol:
matches = smarts.findall(b)
print matches, "\n"
Essentially, the list "search" is a couple of strings I am looking to match in some molecules and I want to iterate over both strings in every molecule contained in allmol using the pybel software. However, the result I get is:
['CCC', 'CCCC']
n= CCC
[(1, 2, 28), (1, 2, 4), (2, 4, 5), (4, 2, 28)]
[]
n= CCCC
[(1, 2, 4, 5), (5, 4, 2, 28)]
[]
as expected except for a couple of extra empty lists slotted in which are messing me up and I cannot see where they are coming from. They appear after the "\n" so are not an artefact of the smarts.findall(). What am I doing wrong?
thanks for any help.
allmol has 2 items and so you're looping twice with matches being an empty list the second time.
Notice how the newline is printed after each; changing that "\n" to "<-- matches" may clear things up for you:
print matches, "<-- matches"
# or, more commonly:
print "matches:", matches
Perhaps it is supposed to end like this
for b in allmol:
matches.append(smarts.findall(b))
print matches, "\n"
otherwise I'm not sure why you'd initialise matches to an empty list
If that is the case, you can instead write
matches = [smarts.findall(b) for b in allmol]
print matches
another possibility is that the file is ending in an empty line
for b in allmol:
if not b.strip(): continue
matches.append(smarts.findall(b))
print matches, "\n"