Python list-of-list idioms - python

data2['C'] is a list that looks like:
[['20120524', '26.31'], ['20120523', '26.08'], ['20120522', '26.52'], ['20120521', '25.75']]
I want to write code that can iterate across d['C'][i][0] and find the list index corresponding to a specific value (a date stored as YYYYMMDD). I still find Python's for loop idioms confusing, and would like clarification on why the first block of code is invalid but the second block of code is valid. Also, if there is a built-in Python function that will do the search procedure I described, please share.
Doesn't work:
>>> print data2['C'][i][0] for i in range(len(data2['C']))
File "<stdin>", line 1
print data2['C'][i][0] for i in range(len(data2['C']))
^
SyntaxError: invalid syntax
Works:
>>> for i in range(len(data2['C'])):
... print data2['C'][i][0]
...
20120524
20120523
20120522
20120521

for can be used in two ways: in an explicit for loop (like your second code block) or in a list/dict/generator comprehension (docs):
print [data2['C'][i][0] for i in range(len(data2['C']))]
Note the brackets. [] means list, {} - a dict and () with for inside - a generator expression.
To have the output identical to the second one, do
print '\n'.join([str(data2['C'][i][0]) for i in range(len(data2['C']))])
or even
print '\n'.join(str(data2['C'][i][0]) for i in range(len(data2['C'])))
This will be a generator expression.

The problem is the first code is a bad list comprehension but the second is a bad iterator. The for in python is a iterator, so, you can do this:
for i in data2['C']:
print i[0]
or
dates = [i[0] for i in data2['C']]
print dates

Related

Python: Index slicing from a list for each index in for loop

I got stuck in slicing from a list of data inside a for loop.
list = ['[init.svc.logd]: [running]', '[init.svc.logd-reinit]: [stopped]']
what I am looking for is to print only key without it values (running/stopped)
Overall code,
for each in list:
print(each[:]) #not really sure what may work here
result expected:
init.svc.logd
anyone for a quick solution?
If you want print only the key, you could use the split function to take whatever is before : and then replace [ and ] with nothing if you don't want them:
list = ['[init.svc.logd]: [running]', '[init.svc.logd-reinit]: [stopped]']
for each in list:
print(each.split(":")[0].replace('[','').replace(']','')) #not really sure what may work here
which gives :
init.svc.logd
init.svc.logd-reinit
You should probably be using a regular expression. The concept of 'key' in the question is ambiguous as there are no data constructs shown that have keys - it's merely a list of strings. So...
import re
list_ = ['[init.svc.logd]: [running]', '[init.svc.logd-reinit]: [stopped]']
for e in list_:
if r := re.findall('\[(.*?)\]', e):
print(r[0])
Output:
init.svc.logd
init.svc.logd-reinit
Note:
This is more robust than string splitting solutions for cases where data are unexpectedly malformed

parse nested function to extract each inner function in python

I have a nested expression as below
expression = 'position(\'a\' IN Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" , "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))'
I want the output as by retreiving nested function first and then outer functions
['Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" , "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" )','position(\'a\' IN Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" , "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))']
Below is the code I have tried
result = []
for i in range(len(expression)):
if expression[i]=="(":
a.append(i)
elif expression[i]==")":
fromIdx=a.pop()
fromIdx2=max(a[-1],expression.rfind(",", 0, fromIdx))
flag=False
for (fromIndex, toIndex) in first_Index:
if fromIdx2 + 1 >= fromIndex and i <= toIndex:
flag=True
break
if flag==False:
result.append(expression[fromIdx2+1:i+1])
But this works only if expression is separated by ','
for ex:
expression = 'position(\'a\' , Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" , "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))'
and result for this expression from my code will be correct as exprected.
In first expression ,I mentioned ,there is IN operator instead of ',' hence my code doesnt work.
Please help
If you want it to be reliable, you need a full-fledged SQL parser. Fortunately, there is an out-of-box solution for that: https://pypi.org/project/sqlparse/. As soon as you have a parsed token tree, you can walk through it and do what you need:
import sqlparse
def extract_functions(tree):
res = []
def visit(token):
if token.is_group:
for child in token.tokens:
visit(child)
if isinstance(token, sqlparse.sql.Function):
res.append(token.value)
visit(tree)
return res
extract_functions(sqlparse.parse(expression)[0])
Explanation.
sqlparse.parse(expression) parses the string and returns a tuple of statements. As there is only one statement in the example, we can just take the first element. If there are many statements, you should rather iterate over all tuple elements.
extract_functions recursively walks over a parsed token tree depth first (since you want inner calls appear before outer ones) using token.is_group to determine if the current token is a leaf, tests if the current token is a function, and if it is, appends its string representation (token.value) to the result list.

pyhamcrest - Compare two list

I've just started learning python. Currently writing a unit test to assert if the elements in the expected list is present in the actual list
def test_compare_list_of_items():
actual_list_of_items = ['a','b']
expected_list_of_items = ['a']
assert_that(actual_list_of_items, has_item(has_items(expected_list_of_items)))
but i'm getting errors like
E Expected: a sequence containing (a sequence containing <['a']>)
E but: was <['a', 'b']>
How and what sequence matcher should i use in order to assert if item 'a' in the expected list is present in the actual list?
You are using has_item when you should only be using has_items. According to the docs this takes multiple matchers which is what you want. Your function then becomes
def test_compare_list_of_items():
actual_list_of_items = ['a','b']
expected_list_of_items = ['a']
assert_that(actual_list_of_items, has_items(*expected_list_of_items))
We use iterable unpacking for the list to feed as the arguments and now when you run it, it shouldn't error out.
I don't know about has_items function, but can you just use something like this?
assertTrue(all(item in expected_list_of_items for item in actual_list_of_items))

How to use append() and make output of loop into new list instead of print

I have a loop I'm using which works great that is:
for i, line in enumerate(lines2):
if "2. Primary Contact Person" in line:
print(*lines[i:i+5], sep="\n")
Which gives me back contact information. So far no issues. But I now want to make the print out and append it into a new list instead of just printing it.
I tried
primary_contact = []
for i, line in enumerate(lines2):
if "2. Primary Contact Person" in line:
primary_contact.append(*lines[i:i+5], sep="\n")
But i get the following error:
TypeError: append() takes no keyword arguments
How would I get this to output to be added into a list?
Using List Comprehension:
primary_contact = ['\n'.join(lines[i:i+5]) for i, line in enumerate(lines2) if "2. Primary Contact Person" in line]
The term:
'\n'.join(lines[i:i+5])
Generates a string equivalent to the earlier output
Python's list.append method takes no additional named arguments. The method append only takes into argument the element which you would like to append to the end of the list. In your case I believe it would be:
primary_contact.append(line)
Depending on what the contents of the actual line looks like, as per your above example - a list slice maybe applicable depending on the actual string you wish to append.

Check if Dictionary Values exist in a another Dictionary in Python

I am trying to compare values from 2 Dictionaries in Python. I want to know if a value from one Dictionary exists anywhere in another Dictionary. Here is what i have so far. If it exists I want to return True, else False.
The code I have is close, but not working right.
I'm using VS2012 with Python Plugin
I'm passing both Dictionary items into the functions.
def NameExists(best_guess, line):
return all (line in best_guess.values() #Getting Generator Exit Error here on values
for value in line['full name'])
Also, I want to see if there are duplicates within best_guess itself.
def CheckDuplicates(best_guess, line):
if len(set(best_guess.values())) != len(best_guess):
return True
else:
return False
As error is about generator exit, I guess you use python 3.x. So best_guess.values() is a generator, which exhaust for the first value in line['full name'] for which a match will not be found.
Also, I guess all usage is incorrect, if you look for any value to exist (not sure, from which one dictinary though).
You can use something like follows, providing line is the second dictionary:
def NameExists(best_guess, line):
vals = set(best_guess.values())
return bool(set(line.values()).intersection(vals))
The syntax in NameExists seems wrong, you aren't using the value and best_guess.values() is returning an iterator, so in will only work once, unless we convert it to a list or a set (you are using Python 3.x, aren't you?). I believe this is what you meant:
def NameExists(best_guess, line):
vals = set(best_guess.values())
return all(value in vals for value in line['full name'])
And the CheckDuplicates function can be written in a shorter way like this:
def CheckDuplicates(best_guess, line):
return len(set(best_guess.values())) != len(best_guess)

Categories

Resources