在列表中查找组合的更优雅的方法是什么?

2024-03-29 07:31:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我想出了这个算法来寻找pairs的三元组(我称之为trairs),标准是所有3个元素(硬币)必须存在于所有3pairs中。在

然而,用一种更优雅的方式来解决同样的问题是可能的。例如,我正在索引所有的循环,这使得它看起来非常复杂。另外,还有一个break让我很不舒服!在

输入数据是pairs,它是strlist
例如pairs = ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC']

想要的输出是一个list的字符串:
例如trair = [['BCH/BTC','BCH/ETH','ETH/BTC]]

def find_trairs(exchange):
    ''' Find possible triplets of pairs (trairs) that can be traded for unbalance.

    Example of trairs:
    'ETC/BTC' 'ETC/ETH' 'ETH/BTC'
    'BCH/BTC' 'BCH/EUR' 'BTC/EUR'

    '''
    exchange_pairs = exchange.symbols #loads all pairs from the exchange.
    pairs = list(filter(lambda x: not '.d' in x, exchange_pairs)) #filters off 
    #the darkpool pairs.

    pair = ['', '', '']
    coin = ['', '', '']
    trair = []

    #Semi-optimized loop to look for triplece of pairs.
    #Example:['BCH/BTC', 'BCH/EUR', 'BTC/EUR']
    for i in range(len(pairs)-3):
        #not all coins are 3 digits long, we must find the slash that separetes
        #each coin in order to have a robust algorithm.
        slash_position = pairs[i].find('/') 
        coin[0] = pairs[i][0:slash_position]
        coin[1] = pairs[i][slash_position+1:]
        for j in range(i+1, len(pairs)-2):
            if (coin[0] in pairs[j]):
                slash_position = pairs[j].find('/') 
                coin[2] = pairs[j][slash_position+1:]
                for k in range(j+1, len(pairs)-1):
                    if coin[1] in pairs[k] and coin[2] in pairs[k]:
                        trair.append([pairs[i], pairs[j], pairs[k]])
                        break

    return trair

有什么提示或意见吗?在


Tags: inforexchangepositionfindeurlisteth
3条回答

以下是一种主要使用标准库功能的方法:

from collections import Counter
from itertools import combinations, chain

raw_pairs = ['BCH/BTC', 'BCH/ETH', 'DASH/USD', 'BTC/USDT', 'ETH/BTC']

def parse_pair(raw_pair):
    return raw_pair.split('/')

def is_trair(trair_candidate):
    # assuming that all currencies appear twice means we have a trair
    currency_counts = Counter(chain.from_iterable(trair_candidate))
    return set(currency_counts.values()) == {2}

pairs = map(parse_pair, raw_pairs)

trair_candidates = combinations(pairs, r=3)

# filter the actual trairs from all trair_candidates
trairs = filter(is_trair, trair_candidates)

print(list(trairs))

将提供:

[(['BCH', 'BTC'], ['BCH', 'ETH'], ['ETH', 'BTC'])]

使用itertools置换,过滤结果并消除重复项:

import itertools

currency_pairs = ['BCH/BTC', 'BCH/ETH', 'DASH/USD', 'BTC/USDT', 'ETH/BTC']
set_triplets = set()
for triplet in itertools.permutations(currency_pairs, 3):
    c1, c2 = triplet[0].split('/')
    if (c1 in triplet[1] or c1 in triplet[2]) and (c2 in triplet[1] or c2 in triplet[2]):
        set_triplets.add(tuple(sorted(triplet)))
for triplet in set_triplets:
    print(triplet)

输出:

^{pr2}$

请注意,三元组中货币对的顺序是按字典顺序升序排列的,不要期望第一对货币对总是连接其他两个货币对。

你可以用

coins = set('/'.join(pairs).split('/'))

去兑换一套所有可能的硬币。然后可以使用itertools.combinations

^{pr2}$

你可以从你的三胞胎中取len 2的组合得到你的“叛徒”。在

trairs = [{frozenset(pair) for pair in combinations(triple, 2)}
          for triple in triples]

结果是一个3项集的列表,其中每个项都是表示一对硬币的冻结集。在


交换可能不直接支持所有可能的对。如果是这样,您可以添加一个额外的过滤器步骤来删除无效的“trairs”。在

pairset = set(frozenset(pair.split('/')) for pair in pairs)
trairs = [trair for trair in trairs if trair <= pairset]

<=检查trair是否是pairset的子集。在


冻结集的列表与问题的结构更匹配,因此它可能满足您的需要,但它并不完全是指定的输出形式。在

您可以使用

[['/'.join(pair) for pair in trair] for trair in trairs]]

集合实际上是无序的,但是这个问题是否重要还不清楚,因为购买例如BTC/ETH与出售{}等是一样的,并且不清楚相同三元组的其他顺序是什么用途。所以你可以把三元组保留为一组,用字母顺序排列的配对。在

[{'/'.join(sorted(pair)) for pair in trair} for trair in trairs]]

相关问题 更多 >