user1903663
user1903663

Reputation: 1725

How can I loop through a Python list and perform math calculations on elements of the list?

I am attempting to create a contract bridge match point scoring system. In the list below the 1st, 3rd, etc. numbers are the pair numbers (players) and the 2nd, 4th etc. numbers are the scores achieved by each pair. So pair 2 scored 430, pair 3 scored 420 and so on.

I want to loop through the list and score as follows:

for each pair score that pair 2 beats they receive 2 points, for each they tie 1 point and where they don't beat they get 0 points. The loop then continues and compares each pair's score in the same way. In the example below, pair 2 gets 7 points (beating 3 other pairs and a tie with 1), pair 7 gets 0 points, pair 6 gets 12 points beating every other pair.

My list (generated from an elasticsearch json object) is:

['2', '430', '3', '420', '4', '460', '5', '400', '7', '0', '1', '430', '6', '480']

The python code I have tried (after multiple variations) is:

nsp_mp = 0
ewp_mp = 0
ns_list = []
for row in arr["hits"]["hits"]:
  nsp = row["_source"]["nsp"]
  nsscore = row["_source"]["nsscore"]
  ns_list.append(nsp)
  ns_list.append(nsscore)

print(ns_list)
x = ns_list[1]
for i in range(6):  #number of competing pairs
  if x > ns_list[1::2][i]:
    nsp_mp = nsp_mp + 2
  elif x == ns_list[1::2][i]:
    nsp_mp = nsp_mp
  else: 
    nsp_mp = nsp_mp + 1
print(nsp_mp)

which produces:

['2', '430', '3', '420', '4', '460', '5', '400', '7', '0', '1', '430', '6', '480']
7

which as per calculation above is correct. But when I try to execute a loop it does not return the correct results.

Maybe the approach is wrong. What is the correct way to do this?

The elasticsearch json object is:

arr = {'took': 0, 'timed_out': False, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}, 'hits': {'total': 7, 'max_score': 1.0, 'hits': [{'_index': 'match', '_type': 'score', '_id': 'L_L122cBjpp4O0gQG0qd', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '2', 'ewp': '9', 'contract': '3NT', 'by': 'S', 'tricks': '10', 'nsscore': '430', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:32.896151'}}, {'_index': 'match', '_type': 'score', '_id': 'MPL122cBjpp4O0gQHEog', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '3', 'ewp': '10', 'contract': '4S', 'by': 'N', 'tricks': '10', 'nsscore': '420', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:33.027631'}}, {'_index': 'match', '_type': 'score', '_id': 'MfL122cBjpp4O0gQHEqk', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '4', 'ewp': '11', 'contract': '3NT', 'by': 'N', 'tricks': '11', 'nsscore': '460', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:33.158060'}}, {'_index': 'match', '_type': 'score', '_id': 'MvL122cBjpp4O0gQHUoj', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '5', 'ewp': '12', 'contract': '3NT', 'by': 'S', 'tricks': '10', 'nsscore': '400', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:33.285460'}}, {'_index': 'match', '_type': 'score', '_id': 'NPL122cBjpp4O0gQHkof', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '7', 'ewp': '14', 'contract': '3NT', 'by': 'S', 'tricks': '8', 'nsscore': '0', 'ewscore': '50', 'timestamp': '2018-12-23T16:45:33.538710'}}, {'_index': 'match', '_type': 'score', '_id': 'LvL122cBjpp4O0gQGkqt', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '1', 'ewp': '8', 'contract': '3NT', 'by': 'N', 'tricks': '10', 'nsscore': '430', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:32.405998'}}, {'_index': 'match', '_type': 'score', '_id': 'M_L122cBjpp4O0gQHUqg', '_score': 1.0, '_source': {'tournament_id': 1, 'board_number': '1', 'nsp': '6', 'ewp': '13', 'contract': '4S', 'by': 'S', 'tricks': '11', 'nsscore': '480', 'ewscore': '0', 'timestamp': '2018-12-23T16:45:33.411104'}}]}}

Upvotes: 1

Views: 1978

Answers (4)

Gaurav
Gaurav

Reputation: 543

I first convert the list of your score to a dictionary object using itertools, then iterating through each key, and for each key, compare the values available in the list and add accordingly the score you provided and since in this approach you will always add the value 1 because you will always compare it with itself so at end i decrease 1 from the final score there may be a better approach for this

ls = ['2', '430', '3', '420', '4', '460', '5', '400', '7', '0', '1', '430', '6', '480']
d = dict(itertools.zip_longest(*[iter(ls)] * 2, fillvalue=""))
values= d.values()
for item in d.keys():
   score=0
   for i in values:
     if d[item]>i:
       score+=2
     elif d[item]==i:
       score+=1
     else:
       pass
   print(item,":",score-1)

Output:

2 : 7
3 : 4
4 : 10
5 : 2
7 : 0
1 : 7
6 : 12

Upvotes: 0

gold_cy
gold_cy

Reputation: 14236

So we can do it like so:

import itertools

d = [(i['_source']['nsp'], i['_source']['nsscore']) for i in arr['hits']['hits']]

d

[('2', '430'),
 ('3', '420'),
 ('4', '460'),
 ('5', '400'),
 ('7', '0'),
 ('1', '430'),
 ('6', '480')]

c = itertools.combinations(d, 2)

counts = {}
for tup in c:
    p1, p2 = tup
    if not counts.get(p1[0]):
        counts[p1[0]] = 0
    if int(p1[1]) > int(p2[1]):
        counts[p1[0]] += 1

counts

{'2': 3, '3': 2, '4': 3, '5': 1, '7': 0, '1': 0}

Upvotes: 0

rvs
rvs

Reputation: 1301

List appears to be a poor data structure for this, I think you are making everything worse by flattening your elasticsearch object.

Note there are a few minor mistakes in listings below - to make sure I'm not solving someone's homework for free. I also realize this is not the most efficient way of doing so.

Try with dicts:

1) convert elasticsearch json you have to a dict with a better structure:

scores = {}
for row in arr["hits"]["hits"]:
  nsp = row["_source"]["nsp"]
  nsscore = row["_source"]["nsscore"]
  scores[nsp] = nsscore

This will give you something like this:

{'1': '430',
 '2': '430',
 '3': '420',
 '4': '460',
 '5': '400',
 '6': '480',
 '7': '0'}

2) write a function to calculate pair score:

def calculate_score(pair, scores):
    score = 0
    for p in scores:
        if p == pair:
            continue
        if scores[p] < scores[pair]:
            score += 2  # win
        elif scores[p] == scores[pair]:
            score += 1
    return score

This should give you something like this:

In [13]: calculate_score('1', scores)
Out[13]: 7

In [14]: calculate_score('7', scores)
Out[14]: 0

3) loop over all pairs, calculating scores. I'll leave this as exercise.

Upvotes: 1

Daniel
Daniel

Reputation: 42778

The main problem with your code is, that the loop is one short, you have 7 entries. Then you should convert the numbers to int, so that the comparison is correct. In your code, you get for ties 0 points. Instead of having a list, with flattend pairs, you should use tuple pairs.

ns_list = []
for row in arr["hits"]["hits"]:
    nsp = int(row["_source"]["nsp"])
    nsscore = int(row["_source"]["nsscore"])
    ns_list.append((nsp, nsscore))

print(ns_list)
x = ns_list[0][1]
nsp_mp = 0
for nsp, nsscore in ns_list:
    if x > nsscore:
        nsp_mp += 2
    elif x == nsscore:
        nsp_mp += 1
print(nsp_mp)

Upvotes: 0

Related Questions