Python CSV 列表中的多个数字

3 投票
2 回答
662 浏览
提问于 2025-04-18 03:28

我写了一个Python脚本,用来把PostgreSQL的输出存储到一个CSV文件中,这个CSV文件的一部分看起来是这样的:

enter image description here

我写了一些代码,逐行提取并将每第二个数字相乘,比如(看上面的照片),对于第二行,0.844 * 0.0 = 0;对于第四行,0.844 * 0.0 * 0.0 * 0.0 = 0。

import sys, os
os.chdir('C:\Users\Heinz\Desktop')
print os.getcwd()

#set up psycopg2 environment
import psycopg2

#driving_distance module
query = """
    select *
    from shortest_path ($$
        select
            gid as id,
            source::int4 as source,
            target::int4 as target,
            pi::double precision as cost,
            pi_rcost::double precision as reverse_cost
        from network
        $$, %s, %s, %s, %s
    )
"""

#make connection between python and postgresql
conn = psycopg2.connect("dbname = 'TC_area' user = 'postgres' host = 'localhost' password = 'xxxx'")
cur = conn.cursor()

#count rows in the table
cur.execute("select count(*) from network")
result = cur.fetchone()
k = result[0] + 1                #number of points = number of segments + 1

#run loops
#import csv module
import csv
import tempfile
import shutil
rs = []
ars = []
i = 1
l = 1
filename = 'test01.csv'
with open(filename, 'wb') as f:
    while i <= k:
        while l <= k:
            cur.execute(query, (i, l, False, True))
            rs.append(cur.fetchall())
            element = list(rs)
            [a[-1] for a in element]
            product = reduce(lambda x,y: x * y, [a[-1] for a in element])
            writer = csv.writer(f, delimiter = ',')
            writer.writerow(product)
            rs = []
            l = l + 1
        l = 1
        i = i + 1


conn.close()

上面的代码可能会生成一个CSV文件,

enter image description here

因为每行的每个元素最后一个位置总是0,所以我在第三列得到了全是0的结果。

我该如何修改我原始脚本中的这两行代码?

[a[-1] for a in element]
product = reduce(lambda x,y: x * y, [a[-1] for a in element])

第一行提取每个子元组中的每第三个元素,但我不想提取每行最后一个子元组中的最后一个元素。

我的目标是乘以每个括号中的每第三个元素,但如果一行中有多个括号,就不包括最后一个;如果一行中只有一个括号,就将这个行的值设为1。


更新#1

我把代码修改成这样,

#run loops
#import csv module
import csv
import tempfile
import shutil
rs = []
ars = []
i = 1
l = 1
filename = 'test01.csv'
with open(filename, 'wb') as f:
    while i <= k:
        while l <= k:
            cur.execute(query, (i, l, False, True))
            rs.append(cur.fetchall())
            element = list(rs)
            [a[-1] for a in element]
            product = 1 if len(element) == 1 else reduce(lambda x,y: x*y, [a[-1] for a in element[:-1]])
            writer = csv.writer(f, delimiter = ',')
            writer.writerow([product])
            rs = []
            l = l + 1
        l = 1
        i = i + 1

我在 writer.writerow([product]) 这一行中把“product”放在了括号里,以防止出现序列预期错误,结果我得到了每列都包含1的CSV文件,

enter image description here


更新#2

我在脚本中稍微改了一下,测试了element的长度,

#run loops
#import csv module
import csv
import tempfile

rs = []
i = 1
l = 1
filename = 'test02.csv'
with open(filename, 'wb') as f:
    cur.execute(query, (2, 3, False, True))
    rs.append(cur.fetchall())
    element = list(rs)
    print len(element)
    [a[-1] for a in element]
    product = reduce(lambda x,y: x*y, [a[-1] for a in element[:-1]], 1)
    writer = csv.writer(f, delimiter = ',')
    writer.writerow(element)
    rs = []

conn.close()

这是输出结果,

len(element) = 1

enter image description here

尽管一行中有2个元素,但Python返回的却是len(element) = 1(在EXCEL中点击B1单元格也可以证明,这个单元格是空的)

我猜在最后的更新中,A列全是1是因为所有元素的长度都等于1,所以下面的代码行无法生成有效的答案。

product = reduce(lambda x,y: x*y, [a[-1] for a in element[:-1]], 1)

我该如何修改脚本以获取元素的真实长度?


更新#3

我想直接得到一个乘积矩阵,因此我写了这个脚本,

import sys, os
os.chdir('C:\Users\Heinz\Desktop')
#print os.getcwd()

#set up psycopg2 environment
import psycopg2

#pgRouting module
query = """
    select *
    from shortest_path ($$
        select
            gid as id,
            source::int4 as source,
            target::int4 as target,
            pi::double precision as cost,
            pi_rcost::double precision as reverse_cost
        from network
        $$, %s, %s, %s, %s
    )
"""

#make connection between python and postgresql
conn = psycopg2.connect("dbname = 'TC_area' user = 'postgres' host = 'localhost' password = 'xxxx'")
cur = conn.cursor()

#count rows in the table
cur.execute("select count(*) from network")
result = cur.fetchone()
k = result[0] + 1                #number of points = number of segments + 1

#import csv module
import csv
import tempfile
import shutil

#run loops
rs = []
i = 1
l = 1
filename = 'rs.csv'
with open(filename, 'wb') as f:
    writer = csv.writer(f, delimiter = ',')
    while i <= k:
        while l <= k:
            cur.execute(query, (i, l, False, True))
            rs.append(cur.fetchall())
            l = l + 1
        l = 1
        writer.writerow(rs)
        rs = []
        i = i + 1


conn.close()

这是CSV文件中的样子,

enter image description here

这次每行中的每个字段都包含查询行的输出,

query, (i, l, False, True)

字段内容不同,例如,

  • 字段A1包含[(1, -1, 0.0)]
  • 字段B1包含[(1, 1, 0.844), (2, -1, 0.0)]

所以现在我需要计算每行每个字段中有多少个元素,并使用mtadd提供的答案脚本来计算乘积。

我能否获取一个字段中元素的数量?

2 个回答

1

在执行以下代码后:

rs.append(cur.fetchall())
element = list(rs)

这个元素变成了一个长度为1的列表,里面唯一的内容就是查询结果中的所有行。你需要把它改成:

element = cur.fetchall()

要计算乘积,可以使用:

product = reduce(lambda x,y: x*y, [a[-1] for a in element[:-1]],1)

将reduce的初始化值设置为1。

1

因为 writerow 需要一个列表作为参数,所以在你的例子中,element 的内容实际上是 [[(2, 2, 0.0), (3, -1, 0.0)]],也就是一个包含子元组的列表的列表。这个子元组的内部列表是通过 fetchall 返回的。

我们逐行看看你的代码,以及它在更新2中为你的示例电子表格生成的内容。

cur.execute(query, (2, 3, False, True))
temp = cur.fetchall()
print temp

这会返回一个元组的列表 [(2,2,0.0), (3,-1,0.0)],这正是你期望的结果。问题出现在:

rs.append(temp)

当你调用 rs.append 时,你把从数据库返回的元组列表放进了另一个列表中,这样就创建了一个包含元组列表的列表,比如 [[(2,2,0.0), (3,-1,0.0)]]。外层列表的长度是1,也就是说,它里面包含了1个元组列表。

element = list(rs)

这会创建一个新的列表,它是 rs 的浅拷贝,但结构上和 rs 是一样的,仍然是一个包含元组列表的列表。

所以,把你的代码改成下面这样的形式应该能解决你的问题:

filename = 'test02.csv'
with open(filename, 'wb') as f:
    cur.execute(query, (2, 3, False, True))
    element = cur.fetchall()
    print len(element)
    if len(element) == 1:
        product = [1]
    else:
        product = reduce(lambda x,y: x*y, [a[-1] for a in element[:-1]], 1)
    writer = csv.writer(f, delimiter = ',')
    writer.writerow(element)

撰写回答