用于从python中的元组列表中删除重复项的函数

时间:2013-11-15 01:32:15

标签: python function duplicates tuples

在函数sqlPull()中,我每隔5秒从MySQL数据库中提取最近的5个条目。在第二个函数dupCatch()中,我试图删除与n相比在n + 1 SQL拉中的重复项。我想只保存唯一的元组列表,但是现在该函数每5秒打印5次相同的元组列表。

在英语中我试图用dupCatch()做的是从sqlPull()中获取数据,初始化和清空列表,并说明变量数据中的所有元组,如果该元组不在空列表中,则添加如果没有,则将lastPull设置为非唯一元组。

显然,我的功能是错误的,但我不确定如何解决它。

import mysql.connector
import datetime
import requests
from operator import itemgetter
import time

run = True

def sqlPull():
    connection = mysql.connector.connect(user='XXX', password='XXX', host='XXXX', database='MeshliumDB')
    cursor = connection.cursor()
    cursor.execute("SELECT TimeStamp, MAC, RSSI FROM wifiscan ORDER BY TimeStamp DESC LIMIT 5;")
    data = cursor.fetchall()
    connection.close()
    time.sleep(5)
    return data

def dupCatch():
    data = sqlPull()
    lastPull = []
    for (TimeStamp, MAC, RSSI) in data:
        if (TimeStamp, MAC, RSSI) not in lastPull:
            newData = data
        else:
            lastPull = data
        print newData

while run == True:
    dupCatch()

这就是我现在得到的输出:

[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]
[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]
[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]
[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]
[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]
[(datetime.datetime(2013, 11, 14, 20, 28, 54), u'E0:CB:1D:36:EE:9D', u' 20'), (datetime.datetime(2013, 11, 14, 20, 28, 53), u'00:1E:8F:75:82:35', u' 21'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'00:1E:4C:03:C0:66', u' 26'), (datetime.datetime(2013, 11, 14, 20, 28, 52), u'78:E4:00:0C:50:DF', u' 33')]

4 个答案:

答案 0 :(得分:1)

假设你只是试图过滤掉相邻的重复,而不是重复的重复......

首先,当您第一次找到lastPull中的元组时,您将设置lastPull = data。这意味着所有后续元组将自动位于lastPull

同时,您每次都要设置lastPullnewData。因此,其中一个将会发生:

  • 如果所有元组都是新元组,您将设置newData(重复)而不是更新lastPull
  • 如果第一个元组是新元组,但至少有一个元组是重复元组,则您将设置newData并更新lastPull
  • 如果第一个元组是重复元素,则只会更新lastPull

这不是你想要的逻辑。我想您想要使用anyall,或者将break置于其中一个条件中,并将else条款放在for子句中但是,我不确定你在这里要做什么。

同时,您的代码每次循环都会print newData。因此,对于每个元组,您将打印所有元组。如上所述,如果第一个元组是新元组,那么它将始终是新元组,否则将是之前的元组。同样,这可能不是你想要的,但我不确定你做什么想要什么。也许你想在循环之外print newData,而不是每次都通过?

最重要的是,你说你想添加的东西到newData列表,但在你的代码中你只是反复替换变量。要将内容添加到列表中,您需要在其上调用append。 (或者extend,如果你有一个新的东西列表可以一次性添加。)

答案 1 :(得分:1)

让我们回到你的英文描述,而不是试图找出你的代码试图做什么并修复它,让我们回到你的英文描述:

  

在英语中我试图用dupCatch()做的是从sqlPull()中获取数据,初始化和清空列表,并说明变量数据中的所有元组,如果该元组不在空列表中,则添加如果没有,则将lastPull设置为非唯一元组。

所以:

seen = set()
def dupCatch():
    data = sqlPull()
    new_data = []
    for (TimeStamp, MAC, RSSI) in data:
        if (TimeStamp, MAC, RSSI) not in seen:
            seen.add((TimeStamp, MAC, RSSI))
            new_data.append((TimeStamp, MAC, RSSI))
    print new_data

或者,更简洁:

seen = set()
def dupCatch():
    data = sqlPull()
    newData = [row for row in data if row not in seen]
    seen.update(newData)
    print new_data

无论哪种方式,这里的诀窍是我们有一个跟踪我们所见过的每一行的集合。所以,对于每一个新行,如果它在那个集合中,我们已经看到它并且可以忽略它;否则,我们不得忽略它,并将其添加到集合中以供日后使用。

第二个版本只是通过一次过滤所有5行来简化事情,然后update一次性使用所有新行,而不是逐行过滤。

seen必须是全局的原因是全局在函数的所有运行中永远存在,所以我们可以用它来跟踪我们见过的每一行;如果我们把它放在函数的本地,那么每次它都是新的,所以我们只跟踪我们在当前批次中看到的行,这不是很有用。

一般来说,全局变量很糟糕。但是,像持久性缓存这样的东西是“一般”规则的例外。他们的全部意义在于他们本地。如果你有一个有意义的对象模型,那么seen作为一个方法dupCatch是一个方法而不是一个全局方面的成员会好得多。如果你有充分的理由将函数定义为另一个函数中的闭包,seen作为闭包的一部分会更好。等等。但除此之外,全球化是最好的选择。


如果您重新组织了一些代码,可以使这更简单:

def pull():
    while True:
        for row in sqlPull():
            yield row
for row in unique_everseen(pull()):
    print row

......甚至:

for row in unique_everseen(chain.from_iterable(iter(sqlPull, None))):
    print row

请参阅Iterators以及接下来的几个教程部分,itertools文档和David M. Beazley's presentations,以了解上一版本的功能。但是对于新手来说,你可能想要坚持使用第二个版本。

答案 2 :(得分:0)

试试这个:

def dupCatch():
    data = sqlPull()
    lastPull = []
    for x in data:
        if x not in lastPull:
            print(x)
        lastPull.append(x)

答案 3 :(得分:0)

问题是lastPull是一个局部变量,因此每次都设置为[],并且不会在函数调用之间保持不变。对于你想要做的事情,你应该使用一个类并存储最后一个拉:

import mysql.connector
import datetime
import requests
import time

class SqlPuller(object):
    def __init__(self):
        self.last_pull = set()

    def pull(self):
        connection = mysql.connector.connect(user='XXX', password='XXX',
                host='XXXX', database='MeshliumDB')
        cursor = connection.cursor()
        cursor.execute("SELECT TimeStamp, MAC, RSSI FROM wifiscan ORDER BY TimeStamp DESC LIMIT 5;")
        data = cursor.fetchall()
        connection.close()
        return data

    def pull_new(self):
        new_data = []
        data = self.pull()
        for item in data:
            if item not in self.last_pull:
                new_data.append(item)
        self.last_pull = set(data)
        return new_data


if __name__ == "__main__":
    sql_puller = SqlPuller()
    while True:
        for item in sql_puller.pull():
            print(item)
            time.sleep(5)