Command to choose next tuple in the list - python

I was wondering if there are any commands to automatically select the next item in the tuple without me having to type it out?
eg.
nul = 0
noofvalue = 5
value = ['a', 'b', 'c', 'd', 'e']
for nul < noofvalue:
file.write(value[0])
what command can i use here to add 1 to 'value' such that when the file loops, instead of using value[0], it uses value[1] instead?
nul = nul + 1
I've googled for the answer and searched, but i don't understand what they are talking about since i'm extremely new to computer coding, so please forgive my ignorance.

I think what you want is enumerate(). I'll add my own example, since your example is a bit weird:
>>> L = ['a', 'b', 'c', 'd', 'e']
>>> for index, value in enumerate(L):
... try:
... print L[index+1] # Prints the next item in the list
... except IndexError:
... print 'End of the list!'
...
b
c
d
e
End of the list!

In Python, you can iterate over a list or tuple in the same way:
for x in value:
do_something(x)

First value = ['a', 'b', 'c', 'd', 'e'] is not tuple, it is a list. In Python to iterate in for loop you can simply do like:
for v in value:
print v # file.write(v)
(I think you have C background where we need index to access elements and iterate over arrays).
if you wants index also then use use `enumerate( any_sequence) function that return (index, value) pairs in list,
>>> list(enumerate(value))
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
so you could do like:
for i, v in enumerate(value):
print i, v
of course if you want to use index explicitly do like:
index = 0
for v in value:
print index, v
index += 1
but this is not Pythonic way so not preferable in genral.

Related

How to order an array and count it in Python?

I want to find only the top 3 distinct items in descending order. If there's a tiebreaker, sort by alphabetical order. If there are 3 items or fewer, returning the distinct list of items is sufficient.
So if I have input of: ["a","a","b","b","c","c","c","d","d","d","d"]
The output will be ["d","c","a"]
Because d has 4 counts, c 3 counts, a and b have the same frequency, but a is alphabetically first.
In MySQL, I would usually use this:
SELECT id, COUNT(*) as frequency FROM mylist GROUP BY id ORDER BY frequency, id
How can I do that in Python?
I use this code based on SAI SANTOH CHIRAG's solution:
def main(output):
arr = sorted(output,key=lambda i:[output.count(i),-ord(i)],reverse=True)
out = []
for i in arr:
if i not in out: out.append(i)
print(out[:3])
but why is the result like this:
Input (stdin) = a a a b b c d d d d
output = ['d']
['d']
['d']
['d']
['d', 'a']
['d', 'a']
['d', 'a']
['d', 'a', 'b']
['d', 'a', 'b']
['d', 'a', 'b']
instead of what I want, which would be:
['d','a','b']
You use sorted and key for that. Try in this way:
arr = sorted(x,key=lambda i:[x.count(i),-ord(i)],reverse=True)
With this you get all the elements in the sorted order in the increase of count and then alphabetical order. Then do this to get all elements only once:
out = []
for i in arr:
if i not in out:
out.append(i)
print(out[:3])
collections.Counter will do:
the_list = ["a","a","b","b","c","c","c","d","d","d","d"]
counter = Counter(sorted(the_list))
top_3 = counter.most_common(3)
at this point, top_3 is of the form [(<entry>, <freq>)] e.g.
[('d', 4), ('c', 3), ('a', 2)]
Take out the first elements from it via list comprehension:
result = [item for item, freq in top_3]
and we get
['d', 'c', 'a']
Notes:
We pass the sorted list to the Counter because otherwise it will break the ties according to the insertion order; sorting forces the insertion order to be the alphabetical order in a way.
.most_common(3) will return at most 3 elements so we are fine e.g. even if only 2 unique entries are there. E.g. if the_list = ["b", "a"], result will be ["a", "b"] even though number of unique elements is less than 3.
you can use Counter from collections
from collections import Counter
inputs = ["a","a","b","b","c","c","c","d","d","d","d"]
counts = Counter(x)
counts.most_common(3)
final = [i[0] for i in counts.most_common]
output for counts.most_common()
[('d', 4), ('c', 3), ('a', 2), ('b', 2)]
Simpler and more efficient than the accepted answer.
>>> a = ["a","a","b","b","c","c","c","d","d","d","d"]
>>> sorted(set(a), key=lambda s: (-a.count(s), s))[:3]
['d', 'c', 'a']
This removes duplicates first and thus counts each string only once. Also, much better to simply negate the count instead of the character code and using reverse sorting. If the strings had multiple characters, you couldn't even use the character code at all.
Another, using two simpler sorts (might actually be faster):
>>> sorted(sorted(set(a)), key=a.count, reverse=True)[:3]
['d', 'c', 'a']

How can I see if a list of tuples contains a specific tuple by knowing the values in this tuple?

I am fairly new to python and therefore, although I have been trying to find a solution to this problem since hours, I cant! I have a list of tuples called list_of_tuples and then another list of tuples which is called finalTuple
and to which I have appended two tuples. What I wanna do is read all of the tuples from the list_of_tuples and figure out if there is already an identical tuple in the list.
If there is one I wanna print a message in the console which indicates that otherwise just append the tuple in the finalTuple. Could someone help me with that? I have tried the following code but it doesnt work:
list_of_tuples = [ ("a","b","c"),
("a","b","c"),
("a","b","d"),
("a","b","d"),
("i","k","l")
]
first_tuple = ("a","b","c")
second_tuple= ("a","b","d")
finalTuple = []
finalTuple.append(first_tuple)
finalTuple.append(second_tuple)
for i in range(len(list_of_tuples)):
# print(listtt[i])
if not(any((list_of_tuples[i]) in j for j in finalTuple)) :
key_value = []
key_value.append(list_of_tuples[i])
finalTuple.append(tuple(key_value))
print("The tuple is appended to the list")
if (any((list_of_tuples[i]) in j for j in finalTuple)) :
print("The value already exists")
The output I am getting on the console is:
PS C:\Users\andri\PythonProjects\mypyth> py test.py
The tuple is appended to the list
The value already exists
The value already exists
The tuple is appended to the list
The value already exists
The value already exists
The tuple is appended to the list
The value already exists
Your if block that checks if the value already exists takes place after the if block that checks if it doesn't, append the value to the list, so the former is always True since the value would be appended to the list even if it did not. You should use an else block for the opposite condition instead. Moreover, to check if a tuple already exists in a list of tuples, you can simply use the in operator instead:
for i in range(len(list_of_tuples)):
if list_of_tuples[i] in finalTuple:
print("The value already exists")
else:
finalTuple.append(list_of_tuples[i])
print("The tuple is appended to the list")
lot = [("a","b","c"),
("a","b","c"),
("a","b","d"),
("a","b","d"),
("i","k","l")]
ft = [("a","b","c"),("a","b","d")]
Use in or not in for membership testing .
>>> for thing in lot:
... if thing in ft:
... print(f'{thing} in ft')
... else:
... ft.append(thing)
('a', 'b', 'c') in ft
('a', 'b', 'c') in ft
('a', 'b', 'd') in ft
('a', 'b', 'd') in ft
>>> ft
[('a', 'b', 'c'), ('a', 'b', 'd'), ('i', 'k', 'l')]
>>>
Or use sets for membership testing.
>>> set(lot).difference(ft)
{('i', 'k', 'l')}
>>> ft.extend(set(lot).difference(ft))
>>> ft
[('a', 'b', 'c'), ('a', 'b', 'd'), ('i', 'k', 'l')]
>>>

python reference preceding items in list loop

I am trying to loop through a list but at the same time make reference to the items before so i can compare.
This is my code:
list1=[(1,'a','hii'),(2,'a','byee'),(3,'a','yoo'),(4,'b','laa'),(5,'a','mehh')]
I want to loop through my list1 tuples such that if the second value in the tuple is the same value as the second value in the tuple before (both =='a'), then concat the third item in the tuple.
output i want:
list2=[('a','hii,byee,yoo'),('b','laa'),('a','mehh')]
What i have tried:
for item in list1:
for item2 in list2:
if item[0]==(item2[0]-1) and item[1]==item2[1]:
print item[2]+','+item2[2]
elif item[0] != item2[0]-1:
continue
elif item[0]==(item2[0]-1) and item[1] != item2[1]:
print item[2]
wrong output
hii,byee
byee,yoo
yoo
laa
From the first 2 output, it seems like the loop only looks at the preceding value but not at say 2 or more value preceding. Hence it only joined 2 words together and not 3 which it should have. The output also ends up having repeats.
How do i get around this?
I was making this WAY harder than it needed to be
def combine(inval):
outval = [inval[0]]
for item in inval[1:]:
if item[0] == outval[-1][0] + 1 and item[1] == outval[-1][1]:
outval[-1] = (item[0], item[1], ",".join([outval[-1][2], item[2]]))
continue
outval.append(item)
return [(item[1], item[2]) for item in outval]
And to test it...
list1 = [(1,'a','hii'),(2,'a','byee'),(3,'a','yoo'),(4,'b','laa'),(5,'a','mehh')]
list2 = [(1,'a','hii'),(3,'a','byee'),(4,'a','yoo'),(5,'b','laa'),(6,'a','mehh')]
list3 = [(1,'a','hoo'),(3,'a','byee'),(5,'a','yoo'),(6,'a','laa'),(7,'a','mehh'),(9, 'b', 'nope')]
for l in (list1, list2, list3):
print "IN:", l
print "OUT:", combine(l)
print
OUTPUT
IN: [(1, 'a', 'hii'), (2, 'a', 'byee'), (3, 'a', 'yoo'), (4, 'b', 'laa'), (5, 'a', 'mehh')]
OUT: [('a', 'hii,byee,yoo'), ('b', 'laa'), ('a', 'mehh')]
IN: [(1, 'a', 'hii'), (3, 'a', 'byee'), (4, 'a', 'yoo'), (5, 'b', 'laa'), (6, 'a', 'mehh')]
OUT: [('a', 'hii'), ('a', 'byee,yoo'), ('b', 'laa'), ('a', 'mehh')]
IN: [(1, 'a', 'hoo'), (3, 'a', 'byee'), (5, 'a', 'yoo'), (6, 'a', 'laa'), (7, 'a', 'mehh'), (9, 'b', 'nope')]
OUT: [('a', 'hoo'), ('a', 'byee'), ('a', 'yoo,laa,mehh'), ('b', 'nope')]
This takes care of both guaranteeing sequential numbers at the 0th-index as well as equal values at the 1st-index.
Edit: I've updated the algorithm according to the requirements. You can group all tuples with the same key by calling group(values, sort=True) or only group adjacent tuples with the same key by calling group(values). This algorithm also gathers all elements after the key for the final tuple instead of only grabbing the third element.
GroupBy does this pretty well. You can group the values by the second element in the tuple. Then for each group, grab all of the third elements in the group and join them into one string:
import itertools
def keySelector(tup):
return tup[1]
def group(values, sort=False):
"""
Group tuples by their second element and return a list of
tuples (a, b) where a is the second element and b is the
aggregated string containing all of the remaining contents
of the tuple.
If sort=True, sort the tuples before grouping. This will
group all tuples with the same key. Otherwise, only adjacent
tuples wth the same key will be grouped.
"""
if sort:
values.sort(key=keySelector)
grouped = itertools.groupby(values, key=keySelector)
result = []
for k, group in grouped:
# For each element in the group, grab the remaining contents of the tuple
allContents = []
for tup in group:
# Convert tuple to list, grab everything after the second item
contents = list(tup)[2:]
allContents.extend(contents)
# Concatenate everything into one string
aggregatedString = ','.join(allContents)
# Add to results
result.append((k, aggregatedString))
return result
vals = [(1,'a','hii','abc','def'),
(2,'a','byee'),
(3,'a','yoo'),
(4,'b','laa'),
(5,'a','mehh','ghi','jkl')]
print(group(vals, sort=True))
Output:
[('a', 'hii,abc,def,byee,yoo,mehh,ghi,jkl'), ('b', 'laa')]
Shortened version with list comprehensions:
def getGroupContents(tuples):
return ','.join(item for tup in tuples for item in list(tup)[2:])
def group(values, sort=False):
if sort:
values.sort(key=keySelector)
grouped = itertools.groupby(values, key=keySelector)
return [(k, getGroupContents(tuples)) for k, tuples in grouped]

Increment the next element based on previous element

When looping through a list, you can work with the current item of the list. For example, if you want to replace certain items with others, you can use:
a=['a','b','c','d','e']
b=[]
for i in a:
if i=='b':
b.append('replacement')
else:
b.append(i)
print b
['a', 'replacement', 'c', 'd', 'e']
However, I wish the replace certain values not based on index i, but based on index i+1. I've been trying for ages and I can't seem to make it work. I would like something like this:
c=['a','b','c','d','e']
d=[]
for i in c:
if i+1=='b':
d.append('replacement')
else:
d.append(i)
print d
d=['replacement','b','c','d','e']
Is there any way to achieve this?
Use a list comprehension along with enumerate
>>> ['replacement' if a[i+1]=='b' else v for i,v in enumerate(a[:-1])]+[a[-1]]
['replacement', 'b', 'c', 'd', 'e']
The code replaces all those elements where the next element is b. However to take care of the last index and prevent IndexError, we just append the last element and loop till the penultimate element.
Without a list comprehension
a=['a','b','c','d','e']
d=[]
for i,v in enumerate(a[:-1]):
if a[i+1]=='b':
d.append('replacement')
else:
d.append(v)
d.append(a[-1])
print d
It's generally better style to not iterate over indices in Python. A common way to approach a problem like this is to use zip (or the similar izip_longest in itertools) to see multiple values at once:
In [32]: from itertools import izip_longest
In [33]: a=['a','b','c','d','e']
In [34]: b = []
In [35]: for c, next in izip_longest(a, a[1:]):
....: if next == 'd':
....: b.append("replacement")
....: else:
....: b.append(c)
....:
In [36]: b
Out[36]: ['a', 'b', 'replacement', 'd', 'e']
I think there's a confusion in your post between the list indices and list elements. In the loop as you have written it i will be the actual element (e.g. 'b') and not the index, thus i+1 is meaningless and will throw a TypeError exception.
I think one of the smallest set of changes you can do to your example to make it work is:
c = ['a', 'b', 'c', 'd', 'e']
d = []
for i, el in enumerate(c[:-1]):
if c[i + 1] == 'b':
d.append('replacement')
else:
d.append(el)
print d
# Output...
# ['replacement', 'b', 'c', 'd']
Additionally it's undefined how you should deal with the boundaries. Particularly when i points to the last element 'e', what should i+1 point to? There are many possible answers here. In the example above I've chosen one option, which is to end the iteration one element early (so we never point to the last element e).
If I was doing this I would do something similar to a combination of the other answers:
c = ['a', 'b', 'c', 'd', 'e']
d = ['replacement' if next == 'b' else current
for current, next in zip(c[:-1], c[1:]) ]
print d
# Output...
# ['replacement', 'b', 'c', 'd']
where I have used a list comprehension to avoid the loop, and zip on the list and a shifted list to avoid the explicit indices.
Try using index of current element to check for the next element in the list .
Replace
if i+1=='b':
with
if c[c.index(i)+1]=='b':

1d list indexing python: enhance MaskableList

A common problem of mine is the following:
As input I have (n is some int >1)
W = numpy.array(...)
L = list(...)
where
len(W) == n
>> true
shape(L)[0] == n
>> true
And I want to sort the list L regarding the values of W and a comparator. My idea was to do the following:
def my_zip_sort(W,L):
srt = argsort(W)
return zip(L[srt],W[srt])
This should work like this:
a = ['a', 'b', 'c', 'd']
b = zeros(4)
b[0]=3;b[1]=2;b[2]=[1];b[3]=4
my_zip_sort(a,b)
>> [(c,1)(b,2)(a,3)(d,4)]
But this does not, because
TypeError: only integer arrays with one element can be converted to an index
thus, I need to do another loop:
def my_zip_sort(W,L):
srt = argsort(W)
res = list()
for i in L:
res.append((L[srt[i]],W[srt[i]]))
return res
I found a thread about a MaskableList, but this does not work for me (as you can read in the comments), because I would not only need to hold or discard particular values of my list, but also need to re-order them:
a.__class__
>> msk.MaskableList
srt = argsort(b)
a[srt]
>> ['a', 'b', 'd']
Concluding:
I want to find a way to sort a list of objects by constraints in an array. I found a way myself, which is kind of nice except for the list-indexing. Can you help me to write a class that works likewise to MaskableList for this task, which has a good performance?
You don't need to extend list do avoid the for-loop. A list-comprehension is sufficient and probably the best you can do here, if you expect a new list of tuples:
def my_zip_sort(W, L):
srt = argsort(W)
return [(L[i], W[i]) for i in srt]
Example:
n = 5
W = np.random.randint(10,size=5)
L = [chr(ord('A') + i) for i in W]
L # => ['A', 'C', 'H', 'G', 'C']
srt = np.argsort(W)
result = [(L[i], W[i]) for i in srt]
print result
[('A', 0), ('C', 2), ('C', 2), ('G', 6), ('H', 7)]

Categories