Replace two characters in tuple element with dictionary value - list

I have a list of tuples (lot):
lot = [('490001', 'A-ARM1'),
('490001', 'A-ARM2'),
('490002', 'B-ARM3')]
Subsequently, I loop through every second tuple element and wish to replace every 'A-' and 'B-' characters by a dictionary value:
from more_itertools import grouper
dict = {'A-': 'ZZ', 'B-': 'XX'}
for el1, el2 in lot:
for i, j in grouper(el2, 2):
if i+j in dict:
lot2 = [ (el2.replace( (i+j), dict[i+j] )) for el1, el2 in lot ]
print(lot2)
After 'lot2 = ' something is going wrong, my output is
['A-ARM1', 'A-ARM2', 'XXARM3'] instead of [ZZARM1', 'ZZARM2', 'XXARM3']
Can anyone give me a hint on how to resolve this? Also, if you think I can write this more elegantly, feel free to let me know. I'm eager to learn. Any help is greatly appreciated.

This might not be the shortest solution, but it should work:
lot2 = []
for el1, el2 in lot:
lookup = el2[:2]
if lookup in dict:
lot2.append(dict[lookup] + el2[2:])
else:
lot2.append(el2)

Related

Python, FOR looping - creating lists

This is my code to create lists, but its so brutal and inelegant, you guys have some idea to make it much smoother?
Thing is, I want to write code, where you could create your own lists, choose how many of them you want to create and how much items each should have - NOT using while loop. I can manage creating certain number of lists by inputing the range in for loop (number_of_lists)
i = 0
number_of_lists = input('How many lists you want to make? >')
for cycle in range(number_of_lists): #this was originaly range(3),
item1 = raw_input('1. item > ') #and will only work now pro-
item2 = raw_input('2. item > ') #perly, if n_o_l is exact. 3
item3 = raw_input('3. item > ')
#everything is wrong with this
print "-------------------" #code, i need it much more au-
#tonomous, than it is now.
if i == 0:
list1 = [item1, item2, item3]
if i == 1:
list2 = [item1, item2, item3]
if i == 2:
list3 = [item1, item2, item3]
i += 1
print list1
print list2
print list3
Thing is I also want to avoid all that 'if i == int' thing.
Now it will only create 3 lists, right, because instead of number_of_lists i originally used integer 3 to make 3 lists.
Now you see my problem I hope. I need to create new lists from input and name them if possible, so instead of list1 i can name it DOGS or w/e.
I need it all much more simple and interconnected, I hope you understand my problem and maybe have some smooth solution, thanks :)
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Ok, I think I got it now - this is new version, doing pretty much what i want it to do:
number_of_lists = input('How many lists you want to make? >')
allItems = []
for cycle in range(int(number_of_lists)):
items = []
number_of_items = input('How much items in this list? >')
for i in range(int(number_of_items)):
item = raw_input(str(i+1) + ". item > ")
items.append(item)
allItems.append(items)
print("-------------------")
print allItems
If anyone has idea how to make this more effective and clear, let me know here! :) thanks for help guyz
You can add your lists to another list, that way it's dynamic like you want. Example below:
number_of_lists = input('How many lists you want to make? >')
allItems = []
for cycle in range(int(number_of_lists)):
items = []
for i in range(1, 4):
item = input(str(i) + ".item > ")
items.append(item)
allItems.append(items)
print("-------------------")
for items in allItems:
for item in items:
print(item)
print("-------------")
You'd still need to check if number_of_lists is an int before parsing it into an int. If the user types a letter it will throw an error.

Python: referring to each duplicate item in a list by unique index

I am trying to extract particular lines from txt output file. The lines I am interested in are few lines above and few below the key_string that I am using to search through the results. The key string is the same for each results.
fi = open('Inputfile.txt')
fo = open('Outputfile.txt', 'a')
lines = fi.readlines()
filtered_list=[]
for item in lines:
if item.startswith("key string"):
filtered_list.append(lines[lines.index(item)-2])
filtered_list.append(lines[lines.index(item)+6])
filtered_list.append(lines[lines.index(item)+10])
filtered_list.append(lines[lines.index(item)+11])
fo.writelines(filtered_list)
fi.close()
fo.close()
The output file contains the right lines for the first record, but multiplied for every record available. How can I update the indexing so it can read every individual record? I've tried to find the solution but as a novice programmer I was struggling to use enumerate() function or collections package.
First of all, it would probably help if you said what exactly goes wrong with your code (a stack trace, it doesn't work at all, etc). Anyway, here's some thoughts. You can try to divide your problem into subproblems to make it easier to work with. In this case, let's separate finding the relevant lines from collecting them.
First, let's find the indexes of all the relevant lines.
key = "key string"
relevant = []
for i, item in enumerate(lines):
if item.startswith(key):
relevant.append(item)
enumerate is actually quite simple. It takes a list, and returns a sequence of (index, item) pairs. So, enumerate(['a', 'b', 'c']) returns [(0, 'a'), (1, 'b'), (2, 'c')].
What I had written above can be achieved with a list comprehension:
relevant = [i for (i, item) in enumerate(lines) if item.startswith(key)]
So, we have the indexes of the relevant lines. Now, let's collected them. You are interested in the line 2 lines before it and 6 and 10 and 11 lines after it. If your first lines contains the key, then you have a problem – you don't really want lines[-1] – that's the last item! Also, you need to handle the situation in which your offset would take you past the end of the list: otherwise Python will raise an IndexError.
out = []
for r in relevant:
for offset in -2, 6, 10, 11:
index = r + offset
if 0 < index < len(lines):
out.append(lines[index])
You could also catch the IndexError, but that won't save us much typing, as we have to handle negative indexes anyway.
The whole program would look like this:
key = "key string"
with open('Inputfile.txt') as fi:
lines = fi.readlines()
relevant = [i for (i, item) in enumerate(lines) if item.startswith(key)]
out = []
for r in relevant:
for offset in -2, 6, 10, 11:
index = r + offset
if 0 < index < len(lines):
out.append(lines[index])
with open('Outputfile.txt', 'a') as fi:
fi.writelines(out)
To get rid of duplicates you can cast list to set; example:
x=['a','b','a']
y=set(x)
print(y)
will result in:
['a','b']

how to convert all the values in a list into keys of a Dictionary in Py2.7

I've below lists,
lists=[ ['arya','egg','milk','butter','bread'],
['Jon','butter','pastrie','yogurt','beer'],
['bran','beer','milk','banana','apples'],]
Each list has values in which the first value is the name of a person and rest of all are some food items. I've a task where I've to create a dictionary with these food items as keys and the person as a value as shown below
dict = { 'egg' : set(['arya']),
'milk': set(['arya','bran']),
'butter' : set(['arya','jon']),
'bread' : set(['arya']),
'pastrie' : set(['jon']),
'milk' : set(['bran'])
} # few keys omitted
This is what I did and stopped, dont know how to proceed further,
food,person = [],[]
for i in lists:
food.append(i[1:])
person.append(i[0])
I was able to seperate the first value of each list and append it to a list
and same with food.
Dont know how to proceed further.
started learning python, Any input is highly helpful. kindly share one or two lines of explanation to enlighten this newbie !
Thank you so much.
Using dictionary method setdefault is helpful here.
You of course don't nee to set the slices to a variable, but it makes it easier to read.
d = {}
for l in lists:
name = l[0]
items = l[1:]
for item in items:
d.setdefault(item, set()).add(name)
Use a collections.defaultdict:
lists = [['arya', 'egg', 'milk', 'butter', 'bread'],
['Jon', 'butter', 'pastrie', 'yogurt', 'beer'],
['bran', 'beer', 'milk', 'banana', 'apples']]
from collections import defaultdict
d = defaultdict(set)
for sub in lists:
for v in sub[1:]:
d[v].add(sub[0])
print(d)
Output:
defaultdict(<class 'set'>,
{'bread': {'arya'}, 'yogurt': {'Jon'}, 'beer': {'Jon', 'bran'},
'banana': {'bran'}, 'butter': {'Jon', 'arya'}, 'milk': {'arya',
'bran'}, 'pastrie': {'Jon'}, 'egg': {'arya'}, 'apples': {'bran'}})
For python3 the syntax is a little nicer:
from collections import defaultdict
d = defaultdict(set)
for name, *rest in lists:
for v in rest:
d[v].add(name)

Way of fast iterating through list

I have a question about iterating through lists.
Let's say i have list of maps with format
def listOfMaps = [ ["date":"2013/05/23", "id":"1"],
["date":"2013.05.23", "id":"2"],
["date":"2013-05-23", "id":"3"],
["date":"23/05/2013", "id":"4"] ]
Now i have a list of two patterns (in reality i have a lot more :D)
def patterns = [
/\d{4}\/\d{2}\/\d{2}/, //'yyyy/MM/dd'
/\d{4}\-\d{2}\-\d{2}/ //'yyyy-MM-dd'
]
I want to println dates only with the "yyyy/MM/dd" and "yyyy-MM-dd" format so i have to go through the lists
for (int i = 0; i < patterns.size(); i++) {
def findDates = listOfMaps.findAll{it.get("word") ==~ patterns[i] ?
dateList << it : "Nothing found"}
}
but i have a problem with this way. What if the list "listOfMaps" gonna be huge? It will take a lot of time to find all patters because this code will have to go through the whole list of patters and the same amount of time it will have to go through list of maps wich in case of huge lists might take a long while :). I tried with forEach inside the findAll clousure it does not work.
So my question is is there any way to go through the list of patterns inside the findAll clousure? For instance sth like this in pseudocode
def findDates = listOfMaps.findAll{it.get("word") ==~ for(){patterns[i]} ? : }
so in that case it goes only once through the listOfMaps list and it iterates through patterns(which always is way way way way smaller than listOfMaps).
I might have an idea to create a function that returns the instance of list, but i'm struggling to implement this :).
Thanks in advance for response.
You could do:
def listOfMaps = [ [date:"2013/05/23", id:"1"],
[date:"2013.05.23", id:"2"],
[date:"2013-05-23", id:"3"],
[date:"23/05/2013", id:"4"] ]
def patterns = [
/\d{4}\/\d{2}\/\d{2}/, //'yyyy/MM/dd'
/\d{4}\-\d{2}\-\d{2}/ //'yyyy-MM-dd'
]
def foundRecords = listOfMaps.findAll { m ->
patterns.find { p ->
m.date ==~ p
}
}

Erlang: List Comprehension to an Existing List

I am trying to create a new list via a list comprehension but want those new values to be included in an existing list.
More specifically, I am try to create a string out of the date and will have some string formatting between the values ( a dash - ). The existing list will be a template if you will with the dash.
Here is what I have so far:
{Date, Time} = erlang:universaltime().
DateList = tuple_to_list(Date).
DateListString = [ integer_to_list(X) || X < DateList ].
DateListStringConcatenate = lists:flatten(DateListString).
The result should be something along
"20101121"
But, what I want is
"2010-11-21"
So I am thinking about the DateListString comprehension "comprehending" to an existing list with "-" after the first and second element.
Any suggestions accompanied with concrete code samples much appreciated.
1> {{Y,M,D},_} = erlang:universaltime().
{{2010,11,21},{16,42,56}}
2> lists:flatten(io_lib:format("~p-~p-~p", [Y,M,D])).
"2010-11-21"
If you really want it in a list comprehension then you could do the following:
{Date, Time} = erlang:universaltime().
DateList = tuple_to_list(Date).
DateListString = [ [$- | integer_to_list(X)] || X <- DateList ].
[_ | DateListStringConcatenate] = lists:flatten(DateListString).
Roberto's is a better/more efficient solution to this but in case you wondered how you might do it with a list comprehension this would be one way.
This is a possible solution, but I feel that it is not an elegant one. Also, it does not use list comprehension.
1> {Date, Time} = erlang:universaltime().
{{2010,11,21},{14,51,23}}
2> DateList = tuple_to_list(Date).
[2010,11,21]
3> DateListString = lists:zipwith(fun(X,Y) -> integer_to_list(X) ++ Y end, DateList, ["-","-",""]).
["2010-","11-","21"]
4> DateListStringConcatenate = lists:flatten(DateListString).
"2010-11-21"