Yunus
Yunus

Reputation: 11

Listing combinations satisfying several conditions

Data:

        Items Category  Value
        apple   Fruits      2
       banana   Fruits      2
       grapes   Fruits      4
         Abhi    Names      5
        Ayush    Names      4
        Krish    Names      3
       Kartik    Names      4
        Paras    Names      3
       School    Place      5
   Playground    Place      4
    Courtyard    Place      1
         Farm    Place      4
        Shirt  Clothes      6
         Pant  Clothes      4
        Jeans  Clothes      1
        Socks  Clothes      2
        Shoes  Clothes      1
 Handkerchief  Clothes      1
       Jacket  Clothes      3
      T-Shirt  Clothes      4

Code:

import pandas as pd
from itertools import permutations, combinations

Grouped = data.groupby(["Category"])
Fruits = Grouped.get_group('Fruits')
Names = Grouped.get_group('Names')
Place = Grouped.get_group('Place')
Clothes = Grouped.get_group('Clothes')

all = combinations([Fruits, Names, Place, Clothes], 6)

for i in all:
    print (i)

I want only 6 items from the possible combinations of all categories (Fruits, Names, Place and Clothes) and the total value of those 6 items mustn't exceed 15.

Also, the combination must contain:

Items    Minimum & Maximum

Fruits  = 1->3
Names   = 2->3
Place   = 1->2
Clothes = 2->4

Upvotes: 0

Views: 136

Answers (1)

VirtualScooter
VirtualScooter

Reputation: 1888

This is a perfect fit for itertools. We'll use combinations() to generate all possible combinations of desired length, and then use filterfalse() to select those that satisfy the conditions.

Using the data from the question, we find 32 combinations that satisfy the conditions out of 38,760 possible combinations.

One complication, and probably the reason that the partial program in the question does not print any combinations, is that a pandas dataframe does not iterate in a straight-forward manner, since a dataframe is really structured object. The solution below uses df.values to get a numpy array of items (each being a list length 3) as input to combinations().

The sample data set from the question can be used as a string input:

datastr = """
        Items Category  Value
        apple   Fruits      2
       banana   Fruits      2
       grapes   Fruits      4
         Abhi    Names      5
        Ayush    Names      4
        Krish    Names      3
       Kartik    Names      4
        Paras    Names      3
       School    Place      5
   Playground    Place      4
    Courtyard    Place      1
         Farm    Place      4
        Shirt  Clothes      6
         Pant  Clothes      4
        Jeans  Clothes      1
        Socks  Clothes      2
        Shoes  Clothes      1
 Handkerchief  Clothes      1
       Jacket  Clothes      3
      T-Shirt  Clothes      4
"""

Using StringIO to load the sample data set as a string:

from io import StringIO
import itertools
import pandas as pd

df = pd.read_table(StringIO(datastr), sep='\s+')
def is_not_valid(t):
    """ t is not a valid tuple if sum > 15 or min/max exceeded """
    t_sum = 0
    if t_sum > 15:
        return True
    for item in t:
        t_sum += item[2]
        if t_sum > 15:
            return True
        if item[1] == 'Fruits' and not 1 <= item[2] <= 3:
            return True
        if item[1] == 'Names' and not 2 <= item[2] <= 3:
            return True
        if item[1] == 'Place' and not 1 <= item[2] <= 2:
            return True
        if item[1] == 'Clothes' and not 2 <= item[2] <= 4:
            return True
    return False

all = itertools.combinations(df.values, 6)

for t in itertools.filterfalse(is_not_valid, all):
    print('(', end='')
    for j,n in enumerate(t):
        print(n[0], end='')
        if j < 6-1:
            print(', ', end='')
    print(')')

Start and finish of the output:

(apple, banana, Krish, Paras, Courtyard, Pant)
(apple, banana, Krish, Paras, Courtyard, Socks)
# ...
(banana, Paras, Courtyard, Pant, Socks, Jacket)
(banana, Paras, Courtyard, Socks, Jacket, T-Shirt)

Upvotes: 1

Related Questions