2016-09-02 1 views
0

У меня есть сценарий, который генерирует конфигурацию для некоторых коммутаторов мобильной связи кампуса. Пользователь должен предоставить набор IP-адресов для конфигурации.Pythonic способ узнать, принадлежит ли IP-адрес в другой подсети

Среди других ограничений эти IP-адреса должны быть в одной и той же/24 подсети (всегда/24). Чтобы избежать опечаток, когда IP находится в другой подсети (что испортило конфигурацию, и это уже произошло), я хотел бы сообщить пользователю, какой IP-адрес неисправен. Я написал следующее, но я чувствую, что может быть лучший способ сделать это.

Предположим, что список этот, где третий IP является неправильным:

ips = ['10.0.0.1', '10.0.0.2', '10.0.10.3', '10.0.0.4', '10.0.0.5'] 

Следующая получает работу:

subnets = set() 
for ip in ips: 
    subnets.add('.'.join(ip.split('.')[0:3])) 
    # This would result in subnet being set(['10.0.10', '10.0.0']) 
if len(subnets) > 1: 
    seen_subnets = defaultdict(list) 

    for sn in subnets: 
     for ip in ips: 
      if sn in ip: 
       seen_subnets[sn].append(ip) 

    suspect = '' 
    for sn in seen_subnets.keys(): 
     if len(seen_subnets[sn]) == 1: 
      suspect = seen_subnets[sn][0] 
    if not suspect: 
     # Do something to tell the user one or more IP's are incorrect 
     # but I couldn't tell which ones 

Примечание: Наименьший список, который я мог бы есть 3, и я основываю это на предположении, что, вероятно, большинство, если не все ошибки, будут всего лишь 1 IP.

Возможно ли более простой способ сделать это? Я считаю, что решение должно основываться на использовании set в любом случае, но мне не показалось, что любой из его методов был бы более полезным, чем это.

+0

@Gerrat вы правы, я смешал несколько строк при фиксации формата, зафиксировал его. – interloper

ответ

1

Что-то, как это будет работать:

from itertools import groupby 

ips = ['10.0.0.1', '10.0.0.2', '10.0.10.3', '10.0.0.4', '10.0.0.5'] 

def get_subnet(ip): 
    return '.'.join(ip.split('.')[:3]) 

groups = {} # group ips by subnet 
for k, g in groupby(sorted(ips), key=get_subnet): 
    groups[k] = list(g) 

# Sort the groups by most common first 
for row, (subnet, ips) in enumerate(
    sorted(groups.iteritems(), key=lambda (k, v): len(v), reverse=True) 
): 
    if row > 0: # not the most common subnet 
     print('You probably entered these incorrectly: {}'.format(ips)) 
+0

Интересно! У меня есть сомнения относительно цикла 'for'. Какова необходимость пропускать 'k' в лямбда, если вы собираетесь использовать' v'? Мне кажется, что это позиционное требование, так что сортировка выполняется по длине значения в dict, а не в ключе, но это моя догадка. – interloper

+1

@interloper: Правильно - это позиционное требование. В этом случае ключевой функции будет передан кортеж. Вы можете назвать его с помощью одной переменной (например, 't', но тогда вам придется сортировать по' t [1] '). Казалось мне более интуитивно понятным. – Gerrat

+0

Спасибо, мне нравится тот факт, что этот ответ позволяет мне сообщать о более чем одной «неправильной» подсети, хотя и маловероятной. – interloper

Смежные вопросы