一、什么是combinations

combinations是Python中的一个函数,它可以返回指定序列中所有长度为n的组合。它的语法如下:

combinations(iterable, r)

其中,iterable表示要求组合的序列;r表示每个组合的长度,通常也称为组合数。

下面是一个简单的例子:

from itertools import combinations

lst = ['a', 'b', 'c']
for i in combinations(lst, 2):
    print(i)

输出结果为:

('a', 'b')
('a', 'c')
('b', 'c')

二、如何使用combinations

1、生成组合列表

combinations可以生成长度为n的组合列表,我们可以将它们存储在一个列表中,以备后续使用。下面是一个例子,我们要取出列表[1, 2, 3, 4]中长度为3的所有组合:

from itertools import combinations

lst = [1, 2, 3, 4]
res = []
for i in range(1, len(lst) + 1):
    res.extend(list(combinations(lst, i)))
    
print(res)

输出结果为:

[(1,), (2,), (3,), (4,), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (1, 2, 3, 4)]

2、使用combinations生成器

如果我们对生成的组合仅仅是遍历取值,不需要将所有组合存储在列表中,那么可以使用combinations生成器,这样可以节约存储空间和计算时间,如下所示:

from itertools import combinations

lst = [1, 2, 3, 4]
for i in range(1, len(lst) + 1):
    for j in combinations(lst, i):
        print(j)

输出结果与上面的例子相同。

3、使用combinations计算总数

在某些情况下,我们需要计算给定列表中组合的总数,这时候可以使用组合数公式。

设有n个元素,要在其中选出r个元素的组合,其组合数为C(n, r)。组合数公式如下:

C(n, r) = n! / (r! * (n - r)!)

下面是一个例子,我们要从列表[1, 2, 3, 4]中选出2个元素的组合,那么总数为:

import math

n = 4  # 元素数量
r = 2  # 组合数
res = math.factorial(n) // (math.factorial(r) * math.factorial(n - r))

print(res)

输出结果为:

6

三、combinations的应用场景

1、密码破解

combinations可以用于密码破解。我们可以生成不同长度的密码组合,进行暴力破解。

import itertools
import string

# 生成长度为n的密码组合
def generate_password(n):
    symbols = ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+"]
    all_chars = string.ascii_letters + string.digits + "".join(symbols)
    for password in itertools.combinations(all_chars, n):
        yield "".join(password)

# 假设密码长度为6
password_length = 6

# 生成所有长度为6的密码组合
passwords = generate_password(password_length)

# 破解密码
real_password = "abc123"
for password in passwords:
    if password == real_password:
        print(f"The password is {password}")
        break

如果将上面的程序运行,可以得到正确的密码“abc123”。

2、数据分析

combinations可以用于数据分析,特别是在大量数据中查找特定的元素组合时非常有用。例如,在一个大的文本文件中,查找特定单词组合的出现次数。

import itertools
import re

# 读取文本文件
def read_text_file(file_path):
    with open(file_path, "r", encoding="utf-8") as f:
        return f.read()

# 统计单词出现次数
def count_word_occurrences(file_path, word_count):
    # 读取文本文件
    text = read_text_file(file_path)

    # 使用正则表达式将文本文件中的单词清洗出来
    words = re.findall(r'\w+', text)

    # 统计单词出现次数
    for word in itertools.combinations(words, word_count):
        key = " ".join(word)
        if key not in word_counts:
            word_counts[key] = 0
        word_counts[key] += 1

    return word_counts

# 假设我们要在文本文件中查找长度为3的单词组合
word_count = 3

# 统计单词出现次数
word_counts = count_word_occurrences("text.txt", word_count)

# 打印结果
for key, value in word_counts.items():
    print(f"{key}: {value}")

上面的程序可以在文本文件”test.txt”中查找长度为3的单词组合的出现次数。

3、百度贴吧数据爬取

combinations可以用于爬取百度贴吧数据。我们可以通过多个关键词构造不同的搜索组合,爬取相关帖子。

import itertools
import requests
from bs4 import BeautifulSoup

# 构造搜索url
def build_search_url(keywords, page_num):
    return f"https://tieba.baidu.com/f?kw={'%20'.join(keywords)}&ie=utf-8&pn={(page_num - 1) * 50}"

# 爬取搜索页数据
def get_search_data(keywords, page_num):
    search_url = build_search_url(keywords, page_num)
    response = requests.get(search_url)
    return response.text

# 解析搜索页数据
def parse_search_data(search_data):
    soup = BeautifulSoup(search_data, "html.parser")
    return soup.select(".threadlist_title a")

# 假设我们要搜索以下两个关键词组合的贴吧帖子:
keywords = ["Python", "机器学习"]

# 假设我们要爬取的页数为2
page_count = 2

# 爬取数据并解析
all_titles = []
for i in range(1, page_count + 1):
    search_data = get_search_data(keywords, i)
    titles = parse_search_data(search_data)
    all_titles.extend(titles)

# 打印结果
for title in all_titles:
    print(title.text.strip())

上面的程序可以爬取关键词“Python”和“机器学习”的贴吧帖子标题。