【问题标题】:How to fill up missing elements in a table?如何填补表格中缺失的元素?
【发布时间】:2016-08-07 05:00:33
【问题描述】:

我的桌子:

New York  3       books        1000
London    2,25                 2000
Paris     1.000   apples       3000
          30                   4000
Berlin            newspapers 

我想保留表格中的空字段,用xxxx 值填充它们并将整个表格放入一个列表中。

New York  3       books        1000
London    2,25    xxxx         2000
Paris     1.000   apples       3000
xxxx      30      xxxx         4000
Berlin    xxxx    newspapers   xxxx

我所做的就是把每一行都捡起来并分开。

finallist = []
for line in range(1,6):
   listtemp = re.split("\s{2,}", line)
   finallist .append(listtemp)

然后我压缩了列表

zippedlist = zip(*finallist)

检查列的长度(现在是行)是否有足够的元素并添加缺少的元素xxxx 添加末尾,但这不起作用,因为它会压缩列(行拆分不会拾取空列中的空格)

我怎样才能用xxxx 元素填充表格并将它们放在这样的列表中:

[['New York','3','books','1000'],['London','2,25','xxxx','2000'],['Paris','1.000','apples','3000'],['xxxx','30','xxxx','4000'],['Berlin','xxxx','newspapers','xxxx']]

另一个表可能是:

New York      3         books   1000  
  London      2,25              2000  
   Paris  1.000                 3000  
             30                 4000  
  Berlin  apples    newspapers 

更新

两个答案都没有给出解决方案,但我用两个都找到了不同的解决方案(经过大量尝试和尝试......)

#list of all lines
r = ['New York      3         books   1000  ', '  London      2,25              2000  ', '   Paris  1.000                 3000  ', '             30                 4000  ', '  Berlin  apples    newspapers ']

#split list
separator = "\s{2,}"
mylist = []
for i in range(0,len(r)):
   mylisttemp = re.split(separator, r[i].strip())
   mylist.append(mylisttemp)

#search for column matches
p = regex.compile("^(?<=\s*)\S|(?<=\s{2,})\S") 

i = []
for n in range(0,len(r)):
   itemp = []
   for m in p.finditer(r[n]):
      itemp.append(m.start())
   i.append(itemp)

#find out which matches are on next lines comparing the column match with all the matches of first line (the one with the smallest difference is the match). 
i_currentcols = []
i_0_indexes = list(range(0,len(i[0])))
for n in range(1,len(mylist)):
   if len(i[n]) == len(i[0]):
      continue
   else:
      i_new = []
      for b in range(0,len(i[n])):
         difference = []
         for c in range(0,len(i[0])): #first line is always correct
             difference.append(abs(i[0][c]-i[n][b]))
         i_new.append(difference.index(min(difference)))
      i_notinside = sorted([elem for elem in i_0_indexes if elem not in i_new ], key=int)
      #add linenr.
      i_notinside.insert(0, str(n))
      i_currentcols.append(i_notinside)

#insert missing fields in list
for n in range(0,len(i_currentcols)):
    for i in range(1,len(i_currentcols[n])):
       mylist[int(i_currentcols[n][0])].insert(i_currentcols[n][i], "xxxx")

【问题讨论】:

  • 您的表格是您构建的文本文件吗?你能保证列长不会改变吗?你能按制表符分割行吗?
  • @Francesco,是的,它在一个文本文件中。列的长度并不总是相同的,它确实会发生变化。编号。列数和行数也是可变的。不,我不能按制表符拆分行。
  • 你能假设列被至少两个连续的空格分隔吗?

标签: python list python-3.x split


【解决方案1】:

我找到了另一个解决方案,它比我之前的答案更易于理解且更通用。

第 1 步:找到切片的位置

我在每一行中搜索space 的职位

t = """New York  3       books        1000
London    2,25                 2000
Paris     1.000   apples       3000
          30                   4000
Berlin            newspapers """

p = re.compile(" ")

i = None
for line in t.split('\n'):
    thisline = set()
    for m in p.finditer(line):
        thisline.add(m.start()+2)
    print sorted(thisline)
    if not i:
        i = thisline
    else:
        i.intersection_update(thisline)
i = sorted(i)

然后我详细说明索引以将后续索引压缩到同一索引中,以便 [10, 11, 17, 18, 19, 30, 31, 32] 变为 [10, 17, 30]

res = []
last = None
for el in i:
    if not last or el != last + 1:
        res.append(el)
    last = el

第 2 步:标记这些位置上的每一行

和以前一样

def split_line_by_indexes( indexes, line ):
    tokens=[]
    indexes = indexes + [len(line)]
    for i1,i2 in zip(indexes[:-1], indexes[1:]): #pairs
        tokens.append( line[i1:i2].rstrip() )
    return tokens

for line in t.split('\n'):
    print split_line_by_indexes(i, line)

结论

这既不完美也不完整。你需要修剪结果,你肯定可以优化代码。

我也看到你找到了解决方案,但我真的很想发布这个,因为我认为值得一试

【讨论】:

    【解决方案2】:

    这是一个非常有趣的问题。我想出了以下简洁的代码。 基本上是 3 行。给定

    s = """New York      3         books   1000  
           London      2,25                2000  
             Paris     1.000                 3000  
                      30                   4000  
           Berlin  apples    newspapers"""
    
    reg = r'^([\w\s]*?)\s+([\d.,]*?)\s+([\w]*?)\s+([\d]*?)$'
    pat = re.compile(reg)
    lines = s.splitlines()
    # lines could be an `open()` file object
    g = (pat.search(line).groups() for line in lines)
    result = ([i if i else "xxx" for i in t] for t in g)
    # consume the result generator
    In [197]: list(result)
    Out[197]:
    [['New York', '3', 'books', '1000'],
     ['London', '2,25', 'xxx', '2000'],
     ['Paris', '1.000', 'apples', '3000'],
     ['xxx', '30', 'xxx', '4000'],
     ['Berlin', 'xxx', 'newspapers', 'xxx']]
    

    看看它是否适合你。如果确实如此,请发表评论,以便我继续告诉您如何使其强大高效

    【讨论】:

    • 如果您考虑评论 “列和行的数量也是可变的。”
    • @Francesco 这不应该。这就是为什么我让我的回答结束了(见最后一行)。如果此类信息已知,则 reg 中的 +/* 可以替换为 {m,n},这将提高效率。但我们谈论的是稳健性。应更改每个组中的字符集[] 以包含适当的字符。在某种程度上,它是一个模式。因此,如果存在可变但 确定 列数,则可以通过在 reg 中添加所有可能的组来使其工作。如果数字是不确定,我现在没有解决方案。
    • @CPanda,感谢您的回答。第二列并不总是数字。您的回答和 Francesco 的回答帮助我找到了不同的解决方案。我已经更新了我的问题。
    • @Reman 看,你可以用正则表达式越具体,性能越好,如果某个组有任意字符,你可以随时使用.*?
    • @CPanda,同意,这不是一个糟糕的解决方案,但使用我目前的解决方案,我不需要调整分离器。拆分器始终相同。
    【解决方案3】:

    这很有挑战性,但我分两步想出了一个解决方案:

    第 1 步:检测列起始位置

    这里的复杂性在于,在某些行中,该列是空的。

    方法是:每个双空格后跟一个非空格字符标识一个新列的开始。 0 始终是列开始。从每一行开始搜索每一列:

    t = """New York  3       books        1000
    London    2,25                 2000
    Paris     1.000   apples       3000
              30                   4000
    Berlin            newspapers """
    
    p = re.compile("  [^ ]")
    
    i = set([0])
    for line in t.split('\n'):
        for m in p.finditer(line):
            i.add(m.start()+2)
    i = sorted(i)
    

    输出:[0,10,18,31]

    第 2 步:标记这些位置上的每一行

    def split_line_by_indexes( indexes, line ):
        tokens=[]
        indexes = indexes + [len(line)]
        for i1,i2 in zip(indexes[:-1], indexes[1:]): #pairs
            tokens.append( line[i1:i2].rstrip() )
        return tokens
    
    for line in t.split('\n'):
        print split_line_by_indexes(i, line)
    

    输出:

    ['New York', '3', 'books', '1000']
    ['London', '2,25', '', '2000']
    ['Paris', '1.000', 'apples', '3000']
    ['', '30', '', '4000']
    ['Berlin', '', 'newspapers', '']
    

    当然,您可以用xxxx 替换空值并将其写回文件,而不是打印

    【讨论】:

    • 感恩。 Faccio 未经测试。 Giusto per la precisione:“列由至少两个连续空格分隔”至少 2 个空格(不总是 2 个空格)。
    • 它在上面的例子中有效,但在这个例子中无效;
    • 它在上面的示例中确实有效,但不适用于我刚刚在问题末尾添加的示例。 (我无法在此评论中向您展示)
    • 第一行总是正确的。下面的行甚至可以有 2 或 3 个连续的空行。
    • @Reman 您发布的第二个示例非常复杂。不仅因为每一列都向右对齐,而且因为第二列与逗号对齐。我有一个解决方案,但非常复杂,我认为您需要对输入进行更多假设才能获得更简单的解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    相关资源
    最近更新 更多