본문 바로가기

개발하자

Python이 중복 출력을 제공하지 않도록 방지

반응형

Python이 중복 출력을 제공하지 않도록 방지

제 목표는 다양한 항목이 중복된 출력 없이 가능한 한 많은 출력을 제공하는 것입니다. 제가 제공한 코드는 제가 작업하고 있는 것의 작은 샘플입니다. 더 큰 데이터 세트의 경우 스크립트가 실행될 때 중복 출력이 CSV 파일을 괴롭힌다는 것을 알 수 있는데, 높은 범위(100, 250, 400 등)를 유지하면서 중복 출력이 처리되지 않도록 하는 방법이 있는지 궁금합니다?

import random
Saying = ["I Like"]

Food = ['Coffee', 'Pineapples', 'Avocado', 'Bacon']
Holiday = ['on the 4th of July', 'on April Fools', 'during Autumn', 'on Christmas']

for x in range(10):
    One = random.choice(Saying)
    Two = random.choice(Food)
    Three = random.choice(Holiday)
    print(f'{One} {Two} {Three}')

도와줘서 고마워요!




우리는 소수와 그 중 하나를 사용하여 정확하게 한 번 간격으로 각 숫자를 방문하는 시퀀스를 만듭니다. 더 구체적으로 말하면, 우리는 의 발전기를 찾고 있다.

우리는 제품보다 약간 큰 소수를 선택해야 하기 때문에 인덱스 오류가 발생하는 경우를 고려해야 합니다.

import random
from math import gcd
import math

from math import prod
from typing import Iterable


def next_prime(number):
    if number < 0:
        raise ValueError('Negative numbers can not be primes')
    if number <= 1:
        return 2
    if number % 2 == 0:
        number -= 1
    while True:
        number += 2
        max_check = int(math.sqrt(number)) + 2
        for divider in range(3, max_check, 2):
            if number % divider == 0:
                break
        else:
            return number


def is_primitive_root(a, n):
    phi = n - 1
    factors = set()
    for i in range(2, int(phi ** 0.5) + 1):
        if phi % i == 0:
            factors.add(i)
            factors.add(phi // i)
    for factor in factors:
        if pow(a, factor, n) == 1:
            return False
    return True


def find_random_primitive_root(n):
    while True:
        a = random.randint(2, n - 1)
        if gcd(a, n) == 1 and is_primitive_root(a, n):
            return a


class CoordinateMapper:
    """
        A class that maps linear indices to multi-dimensional coordinates within a specified shape.

        Args:
            dims (Iterable[int]): An iterable representing the dimensions of the desired shape.

        Example Usage:
            shape = (2, 3, 5, 4)
            mapper = CoordinateMapper(shape)
            coordinates = mapper.map(10)
            print(coordinates)  # Output: [0, 1, 2, 2]
    """

    def __init__(self, dims: Iterable[int]):
        self.moduli = [prod(dims[i:]) for i in range(len(dims))]
        self.divisors = [prod(dims[i + 1:]) for i in range(len(dims))]

    def map(self, n: int):
        return [(n % self.moduli[i]) // self.divisors[i] for i in range(len(self.moduli))]


def sampler(l):
    close_prime = next_prime(l)
    state = root = find_random_primitive_root(close_prime)
    while state > l:
        state = (state * root) % close_prime  # Inlining the computation leads to a 20% speed up

    yield state - 1
    for i in range(l - 1):
        state = (state * root) % close_prime
        while state > l:
            state = (state * root) % close_prime
        yield state - 1


def _unique_combinations(*iterables):
    cartesian_product_cardinality = prod([len(i) for i in iterables])
    coordinate_mapper = CoordinateMapper([len(i) for i in iterables])
    sequence = sampler(cartesian_product_cardinality)
    for state in sequence:
        yield tuple(iterable[coord] for iterable, coord in zip(iterables, coordinate_mapper.map(state)))

나는 다양한 접근법을 벤치마킹하기 시작했다. 어설션 오류 없이 실행할 수 있는 솔루션은 @achint 이외에 없습니다:

from itertools import product
import time
approaches= {
    'prime_roots':_unique_combinations,
    'matmarbon':random_order_cartesian_product,
    'itertools.product':itertools.product,
}
a = list(range(10))
b = list(range(10))
for name, approach in approaches.items():
    assert sorted(u)==sorted(product(a,b))

2개의 알고리즘에 대해 나는 다음을 벤치마킹했고, 기준으로 iter 툴을 사용했다

import pandas as pd
import timeit
import matplotlib.pyplot as plt

def benchmark(approaches, list_lengths, num_repetitions):
    results = []

    for approach, function in approaches.items():
        for length in list_lengths:
            a = list(range(length))
            b = list(range(length))
            def f():
                for item in function(a,b):
                    pass
            execution_time = timeit.timeit(f, number=num_repetitions)
            entry = {
                'Approach': approach,
                'List Length': length,
                'Execution Time': execution_time
            }
            print(entry)
            results.append(entry)

    results_df = pd.DataFrame(results)

    # Plot the benchmark results
    plt.figure(figsize=(10, 6))
    for approach in approaches.keys():
        approach_results = results_df[results_df['Approach'] == approach]
        plt.plot(approach_results['List Length'], approach_results['Execution Time'], marker='o', label=approach)

    plt.xlabel('List Length')
    plt.ylabel('Execution Time (seconds)')
    plt.title('Benchmark Results')
    plt.grid(True)
    plt.legend()
    plt.show()

list_lengths = [10,20,30,40,50,60,70,80,90,100,200,300,400,500]
num_repetitions = 3
benchmark(approaches, list_lengths, num_repetitions)

두 알고리즘 모두 에서 수행됩니다(어느 정도 균등한 크기의 반복 가능한 것으로 가정).

메모리 측면에서 원시 루트 접근법은 메모리만 필요하고 아무것도 저장되지 않기 때문에 승리한다.

분포적으로 원시적인 접근법은 실제로 무작위적인 것이 아니라 예측하기 어려운 결정적인 순서이다. 실제로 시퀀스는 충분히 "랜덤"이어야 합니다.

해결책에 영감을 준 것은 이것에 대한 공로입니다.




이미 본 요소와 함께 사용한 다음 평균 O(1)의 복잡도를 가진 에서 해당 요소가 보이는지 확인할 수 있습니다.

다른 옵션은 목록을 섞고 일부 요소를 팝업하는 것입니다:

import random

random.shuffle(lst)

while lst:
    element = x.pop()



매개 변수와 함께 사용할 수 있습니다. 또한 인수를 사용하여 원하는 만큼 샘플을 샘플링할 수 있습니다.

import numpy as np

Food = ['Coffee', 'Pineapples', 'Avocado', 'Bacon']
Holiday = ['on the 4th of July', 'on April Fools', 'during Autumn', 'on Christmas']

np.random.choice(Food, size=4, replace=False)
>>> array(['Avocado', 'Coffee', 'Pineapples', 'Bacon'], dtype='<U10')

np.random.choice(Holiday, size=4, replace=False)
>>> array(['on April Fools', 'on the 4th of July', 'during Autumn',
       'on Christmas'], dtype='<U18')



문제는 당신의 봇(내 생각엔?)입니다 지금까지 출력된 내용에 대한 기억이 없기 때문에 당신이 가지고 있는 코드로 확인할 방법이 없습니다.

대신 이것으로 시도해 보십시오:

import random
Saying = ["I Like"]

Food = ['Coffee', 'Pineapples', 'Avocado', 'Bacon']
Holiday = ['on the 4th of July', 'on April Fools', 'during Autumn', 'on Christmas']

memory=[]
done = False

while not done:
    One = random.choice(Saying)
    Two = random.choice(Food)
    Three = random.choice(Holiday)

    if f'{One} {Two} {Three}' not in memory:
        memory.append(f'{One} {Two} {Three}')
        if len(memory) == 10:
            done = True

[print(item) for item in memory]

그래서 이제 우리는 10개의 문구를 만드는 데 10개의 팟샷을 찍는 대신, 10개의 다른 문구를 만드는 데 필요한 만큼의 양을 가져갑니다.




다음과 같은 방법으로 비중복 데이터를 유지하면서 랜덤 출력을 생성할 수 있습니다:

  1. 처음에는 기본적으로 순열할 목록의 곱인 목록을 만듭니다.
permutations = list(itertools.product(*Statement))
## Example - [('I Like', 'Coffee', 'on the 4th of July'), ('I Like', 'Coffee', 'on April Fools'), ('I Like', 'Coffee', 'during Autumn'), ('I Like', 'Coffee', 'on Christmas')]
  1. 인덱스를 임의로 선택하여 인쇄하여 에서 요소를 선택합니다.
 num = int(random.random() * total_elements)
 print '{} {} {}'.format(permutations[num][0], permutations[num][1], permutations[num][2])
  1. 그런 다음 중복을 방지하기 위해 목록에서 요소를 제거합니다.
del permutations[num]

전체 코드:

import itertools, random
Saying = ["I Like"]

Food = ['Coffee', 'Pineapples', 'Avocado', 'Bacon']
Holiday = ['on the 4th of July', 'on April Fools', 'during Autumn', 'on Christmas']

Statements = [Saying, Food, Holiday]

permutations = list(itertools.product(*Statements))

random.seed()

total_elements = len(Saying) * len(Food) * len(Holiday)

while total_elements > 0:
    num = int(random.random() * total_elements)
    print '{} {} {}'.format(permutations[num][0], permutations[num][1], permutations[num][2])
    del permutations[num]
    total_elements = total_elements - 1

반응형