基于第一个字符拆分列表 - Python

时间:2015-01-26 11:27:42

标签: python list python-2.7

我是Python的新手,无法找到解决问题的方法。我想根据列表项的开头将列表拆分为两个列表。我的列表看起来像这样,每行代表一个项目(是的,这不是正确的列表符号,但为了更好的概述,我会留下这样的):

***
**
.param
+foo = bar
+foofoo = barbar
+foofoofoo = barbarbar
.model
+spam = eggs
+spamspam = eggseggs
+spamspamspam = eggseggseggs

所以我想要一个包含以' +'开头的所有行的列表.param和.model之间的另一个列表,其中包含以' +'开头的所有行模特直到结束。

我查看了enumerate()和split(),但由于我有一个列表而不是字符串,并且我没有尝试匹配列表中的所有项目,所以我不确定如何实现它们。 我有这个:

paramList = []
for line in newContent:
    while line.startswith('+'):
        paramList.append(line)
        if line.startswith('.'):
            break

这只是我尝试创建第一个列表。问题是,代码也读取了第二个' +' s,因为break只退出while循环,而不是for循环。 我希望你能理解我的问题,并提前感谢任何指示!

4 个答案:

答案 0 :(得分:2)

data = {}
for line in newContent:
    if line.startswith('.'):
        cur_dict = {}
        data[line[1:]] = cur_dict
    elif line.startswith('+'):
        key, value = line[1:].split(' = ', 1)
        cur_dict[key] = value

这会产生一个dicts的字典:

{'model': {'spam': 'eggs',
           'spamspam': 'eggseggs',
           'spamspamspam': 'eggseggseggs'},
 'param': {'foo': 'bar',
           'foofoo': 'barbar',
           'foofoofoo': 'barbarbar'}}

答案 1 :(得分:1)

  

我是Python的新手

糟糕。不要再烦我的回答了。

  

我想要一个包含所有以'+'开头的行的列表   .param和.model以及包含所有行开头的另一个列表   在模型之后使用'+'直到结束。

import itertools as it
import pprint

data = [
    '***',
    '**',
    '.param',
    '+foo = bar',
    '+foofoo = barbar',
    '+foofoofoo = barbarbar',
    '.model',
    '+spam = eggs',
    '+spamspam = eggseggs',
    '+spamspamspam = eggseggseggs',
]

results = [
    list(group) for key, group in it.groupby(data, lambda s: s.startswith('+'))
    if key
]


pprint.pprint(results)
print '-' * 20
print results[0]
print '-' * 20
pprint.pprint(results[1])

--output:--
[['+foo = bar', '+foofoo = barbar', '+foofoofoo = barbarbar'],
 ['+spam = eggs', '+spamspam = eggseggs', '+spamspamspam = eggseggseggs']]
--------------------
['+foo = bar', '+foofoo = barbar', '+foofoofoo = barbarbar']
--------------------
['+spam = eggs', '+spamspam = eggseggs', '+spamspamspam = eggseggseggs']

这件事:

it.groupby(data, lambda x: x.startswith('+')

...告诉python根据字符串的第一个字符创建字符串组。如果第一个字符是'+',则字符串将被置于True组中。如果第一个字符不是'+',则字符串将被置于False组中。但是,有两个以上的组,因为连续的False字符串将形成一个组,连续的True字符串将形成一个组。

根据您的数据,前三个字符串:

***
**
.param

将创建一个False组。然后,接下来的字符串:

+foo = bar
+foofoo = barbar
+foofoofoo = barbarbar

将创建一个True组。然后是下一个字符串:

'.model'

将创建另一个False组。然后是下一个字符串:

'+spam = eggs'
'+spamspam = eggseggs'
'+spamspamspam = eggseggseggs'

将创建另一个True组。结果将是:

{
    False: [strs here],
    True:  [strs here],
    False: [strs here],
    True:  [strs here]
}

然后,只需选择每个True组:if key,然后将相应的组转换为列表:list(group)

对评论的回应:

  

python究竟在哪里通过数据,就像它知道的那样   它正在迭代的数据?

groupby()的工作方式如下面的do_stuff():

def do_stuff(items, func):
    for item in items:
        print func(item)


#Create the arguments for do_stuff():

data = [1, 2, 3]

def my_func(x):
    return  x + 100 

#Call do_stuff() with the proper argument types:

do_stuff(data, my_func) #Just like when calling groupby(), you provide some data 
                        #and a function that you want applied to each item in data

--output:--
101
102
103

也可以这样写:

do_stuff(data, lambda x: x + 100)

lambda创建一个匿名函数,这对于您不需要通过名称引用的简单函数很方便。

列表理解

[ 
    list(group) 
    for key, group in it.groupby(data, lambda s: s.startswith('+')) 
    if key 
]

等同于

results = []

for key, group in it.groupby(data, lambda s: s.startswith('+') ):
   if key:
       results.append(list(group))

显式编写for循环更清楚,但列表推导执行得更快。这是一些细节:

[ 
    list(group)  #The item you want to be in the results list for the current iteration of the loop here:
    for key, group in it.groupby(data, lambda s: s.startswith('+')) #A for loop
    if key #Only include the item for the current loop iteration in the results list if key is True
]

答案 2 :(得分:1)

你想要的是一个简单的任务,可以使用列表切片和列表理解来完成:

data = ['**','***','.param','+foo = bar','+foofoo = barbar','+foofoofoo = barbarbar',
     '.model','+spam = eggs','+spamspam = eggseggs','+spamspamspam = eggseggseggs']

# First get the interesting positions.
param_tag_pos = data.index('.param')
model_tag_pos = data.index('.model')
# Get all elements between tags.
params =  [param for param in data[param_tag_pos + 1: model_tag_pos] if param.startswith('+')]
models =  [model for model in data[model_tag_pos + 1: -1] if model.startswith('+')]

print(params)
print(models)

输出

>>> ['+foo = bar', '+foofoo = barbar', '+foofoofoo = barbarbar']
>>> ['+spam = eggs', '+spamspam = eggseggs']

回答评论:

假设您有一个包含0到5之间的数字的列表。

l = [0, 1, 2, 3, 4, 5]

然后使用列表slices,您可以选择l的一个子集:

another = l[2:5]   # another is [2, 3, 4]

我们在这里做的是:

data[param_tag_pos + 1: model_tag_pos]

对于你的上一个问题: ... python如何知道param是它应该迭代的数据中的行以及paramdo的第一个paramin param到底是什么?

Python不知道,你必须告诉他。

首先param是我在这里使用的变量名称,它是xlist_items,无论你想要什么。

我会将代码行翻译成普通英语:

# Pythonian
params =  [param for param in data[param_tag_pos + 1: model_tag_pos] if param.startswith('+')]

# English
params is a list of "things", for each "thing" we can see in the list `data` 
from position `param_tag_pos + 1` to position `model_tag_pos`, just if that "thing" starts with the character '+'.

答案 3 :(得分:0)

我建议一步一步做。
1)分别从阵列中抓取每个单词。
2)抓住单词的第一个字母。
3)看看那是'+'还是'。'

示例代码:

import re
class Dark():
    def __init__(self):
        # Array 
        x = ['+Hello', '.World', '+Hobbits', '+Dwarves', '.Orcs']
        xPlus = []
        xDot = []
        # Values
        i = 0
        # Look through every word in the array one by one. 
        while (i != len(x)):
            # Grab every word (s), and convert to string (y).
            s = x[i:i+1]
            y = '\n'.join(s)
            # Print word
            print(y)
            # Grab the first letter.
            letter = y[:1]
            if (letter == '+'):
                xPlus.append(y)
            elif (letter == '.'):
                xDot.append(y)
            else:
                pass
            # Add +1
            i = i + 1
        # Print lists
        print(xPlus)
        print(xDot)

#Run class
Dark()