是否有一种简短的方法可以在不使用'if'和多个'and'的情况下检查值的唯一性?

时间:2019-06-22 14:55:39

标签: python duplicates

我正在编写一些代码,我需要比较一些值。关键是所有变量都不应该具有相同的值。例如:

import React from 'react';
import { Platform, StatusBar, StyleSheet, View, AsyncStorage} from 'react-native';
import { AppLoading, Asset, Font, Icon } from 'expo';

import AppNavigator from './navigation/AppNavigator';
import MainTabNavigator from './navigation/MainTabNavigator';
import * as firebase from 'firebase';



export default class App extends React.Component {
  state = {
    isLoadingComplete: false,
    isAuthenticationReady: false,
    isAuthenticated: false,
  };

  render() {
    if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
      return (
        <AppLoading
          startAsync={this._loadResourcesAsync}
          onError={this._handleLoadingError}
          onFinish={this._handleFinishLoading}
        />
      );
    } else {
      return (
        <View style={styles.container}>
          {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
          <AppNavigator />
        </View>
      );
    }
  }

  _loadResourcesAsync = async () => {
    return Promise.all([
      Asset.loadAsync([
        require('./assets/images/robot-dev.png'),
        require('./assets/images/robot-prod.png'),
      ]),
      Font.loadAsync({
        // This is the font that we are using for our tab bar
        ...Icon.Ionicons.font,
        // We include SpaceMono because we use it in HomeScreen.js. Feel free
        // to remove this if you are not using it in your app
        'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
      }),
    ]);
  };


现在,很容易看到在具有更多变量的代码的情况下,a=1 b=2 c=3 if a != b and b != c and a != c: #do something 语句变得很长,充满了if s。有没有一种简短的方法来告诉Python,没有2个变量值应该相同。

5 个答案:

答案 0 :(得分:45)

您可以尝试进行设置。

a, b, c = 1, 2, 3
if len({a,b,c}) == 3:
   # Do something

如果将变量保存为列表,它将变得更加简单:

a = [1,2,3,4,4]
if len(set(a)) == len(a):
    # Do something

Here是python集的官方文档。

这仅适用于问题中给出的可哈希对象(例如整数)。对于非哈希对象,请参见@chepner的more general solution

这绝对是您应该使用可哈希对象的方式,因为对象数量 n 花费O(n)时间。不可散列对象的组合方法需要O(n ^ 2)的时间。

答案 1 :(得分:25)

假设不能使用散列,请使用itertools.combinationsall

from itertools import combinations

if all(x != y for x, y in combinations([a,b,c], 2)):
    # All values are unique

答案 2 :(得分:19)

这取决于您拥有的值的类型。

如果它们表现良好且可哈希化,那么您可以(如其他人已经指出的那样)简单地使用set来找出您拥有多少个唯一值,如果它们不等于总值的数量您至少有两个相等的值。

def all_distinct(*values):
    return len(set(values)) == len(values)

all_distinct(1, 2, 3)  # True
all_distinct(1, 2, 2)  # False

哈希值和惰性值

如果您确实有很多值,并且想在找到一个匹配项后立即中止,则也可以延迟创建该集合。如果所有值都不相同,它会更复杂,并且可能会更慢,但如果发现重复项,则会短路:

def all_distinct(*values):
    seen = set()
    seen_add = seen.add
    last_count = 0
    for item in values:
        seen_add(item)
        new_count = len(seen)
        if new_count == last_count:
            return False
        last_count = new_count
    return True

all_distinct(1, 2, 3)  # True
all_distinct(1, 2, 2)  # False

但是,如果值不可哈希,则将无法正常工作,因为set需要哈希值。

不可散列的值

如果没有哈希值,则可以使用普通列表存储已处理的值,然后检查列表中是否已包含每个新项:

def all_distinct(*values):
    seen = []
    for item in values:
        if item in seen:
            return False
        seen.append(item)
    return True

all_distinct(1, 2, 3)  # True
all_distinct(1, 2, 2)  # False

all_distinct([1, 2], [2, 3], [3, 4])  # True
all_distinct([1, 2], [2, 3], [1, 2])  # False

这会比较慢,因为检查值是否在列表中需要将其与列表中的每个项目进行比较。

(第三方)库解决方案

如果您不介意其他依赖关系,也可以将我的一个库(在PyPi和conda-forge上可用)用于此任务iteration_utilities.all_distinct。此函数可以处理可哈希值和不可哈希值(以及它们的混合):

from iteration_utilities import all_distinct

all_distinct([1, 2, 3])  # True
all_distinct([1, 2, 2])  # False

all_distinct([[1, 2], [2, 3], [3, 4]])  # True
all_distinct([[1, 2], [2, 3], [1, 2]])  # False

一般评论

请注意,上述所有方法都依赖于这样一个事实,即相等意味着“不等于”(几乎)所有内置类型都是这种情况,但不一定如此!

但是我想指出chepners answers,它不需要对值进行散列,并且并不通过显式检查{{ 1}}。它还会短路,因此其行为类似于您最初的!=方法。

性能

要大致了解性能,我正在使用我的另一个库(simple_benchmark

我使用了不同的可哈希输入(左)和不可哈希输入(右)。对于可散列的输入,设置方法的效果最好,而对于不可散列的输入,列表方法的效果更好。在两种情况下,基于and的方法似乎最慢:

enter image description here

我还测试了有重复的情况下的性能,为方便起见,我考虑了前两个元素相等的情况(否则设置与前面的情况相同):

enter image description here

combinations

答案 3 :(得分:1)

稍微整洁的方法是将所有变量粘贴在列表中,然后从列表中创建一个新集合。如果列表和集合的长度不同,则某些变量相等,因为集合不能包含重复项:

vars = [a, b, c]
no_dupes = set(vars)

if len(vars) != len(no_dupes):
    # Some of them had the same value

这假定值是可哈希的;它们在您的示例中。

答案 4 :(得分:0)

您也可以将alllist.count一起使用,这是合理的,可能不是最好的方法,但是值得回答:

>>> a, b, c = 1, 2, 3
>>> l = [a, b, c]
>>> all(l.count(i) < 2 for i in l)
True
>>> a, b, c = 1, 2, 1
>>> l = [a, b, c]
>>> all(l.count(i) < 2 for i in l)
False
>>> 

此解决方案还适用于列表中不可散列的对象。

仅适用于列表中的可哈希对象的方法:

>>> a, b, c = 1, 2, 3
>>> l = [a, b, c]
>>> len({*l}) == len(l)
True
>>> 

实际上:

>>> from timeit import timeit
>>> timeit(lambda: {*l}, number=1000000)
0.5163292075532642
>>> timeit(lambda: set(l), number=1000000)
0.7005311807841572
>>> 

{*l}set(l)更快,更多信息here