Python中将对象列表转换为指定字典结构的方法咨询
Hey there! Let's break this down step by step—you're totally on the right track, and we can fix those frustrating issues you ran into with loops and list comprehensions.
First: Get the String Before the First Underscore
You asked if there's a Python equivalent of substr('_') to grab everything before the first underscore. Yep, it's super straightforward with the split() method:
name = 'a_1_1' letter = name.split('_', 1)[0] # Returns 'a'
The second argument 1 tells split() to only split once, so even if there are more underscores later, we just grab the first segment. This is efficient and exactly what you need.
Second: Convert Your Object List to the Target Structure
Let's tackle the main problem: turning your list of old_type objects into a list of dictionaries (or custom objects) with letter, indices, and value keys.
First, let's recap the logic we need for each object:
- Split the
nameby underscores to separate the letter and index parts - Convert the index strings to integers
- If there's only one index, store it as a single integer; if multiple, store as a list of integers
- Map the
valuedirectly from the old object
Option 1: Using a Simple Loop (Easy to Debug)
If list comprehensions felt too confusing, a plain loop is totally fine—this avoids the "overwriting data" issue because we create a new dictionary for each object:
# Assume your old list is called old_objects new_data = [] for obj in old_objects: # Split the name into parts name_parts = obj.name.split('_') letter = name_parts[0] # Get index parts and convert to integers index_strings = name_parts[1:] indices = [int(idx) for idx in index_strings] # If only one index, use a single integer instead of a list if len(indices) == 1: indices = indices[0] # Add the new dictionary to the list new_data.append({ 'letter': letter, 'indices': indices, 'value': obj.value })
Option 2: Using a List Comprehension (Concise)
If you prefer a more compact version, this list comprehension does the same thing without the nested loops that caused "too deep" lists:
new_data = [ { 'letter': parts[0], 'indices': int(parts[1]) if len(parts[1:]) == 1 else [int(p) for p in parts[1:]], 'value': obj.value } for obj in old_objects for parts in [obj.name.split('_')] # Trick to split once per object ]
Why Your Previous Attempts Failed
- Overwriting data: You probably reused the same dictionary in your loop instead of creating a new one each time. By defining
{...}inside the loop (or comprehension), we make a fresh dictionary for every object. - Too deep lists: You might have nested an extra loop over the index parts inside the list comprehension. The trick above uses
for parts in [obj.name.split('_')]to split once and reuse the parts without adding an extra level of nesting.
Bonus: Using Custom Objects (Instead of Dictionaries)
If you want a more structured type than dictionaries, you can use a dataclass (Python 3.7+):
from dataclasses import dataclass @dataclass class NewDataType: letter: str indices: int | list[int] # Supports both single int and list of ints value: any # Convert the list new_data = [] for obj in old_objects: name_parts = obj.name.split('_') letter = name_parts[0] index_strings = name_parts[1:] indices = [int(idx) for idx in index_strings] if len(indices) == 1: indices = indices[0] new_data.append(NewDataType(letter, indices, obj.value))
Now you can access attributes like new_data[0].letter just like you wanted!
Testing with Your Example
Using your sample input:
class old_type: def __init__(self, name, value): self.name = name self.value = value old_objects = [old_type('a_1_1',4), old_type('a_1_2',2), old_type('x_1',True)]
The resulting new_data will be exactly what you described:
new_data[0]hasletter='a',indices=[1,1],value=4new_data[2]hasletter='x',indices=1,value=True
内容的提问来源于stack exchange,提问作者Finn

