Python Forum

Full Version: Flatten list sublists
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi guys! I have this list:

 mylist = ["Hello", ["Hello2", "Hello3"], "Hello4"]
However, I want the list to be this instead (don't say just remove the sublist. This is not the real list. Just a test list. The real list comes from a function return so that wouldn't work):

 mylist = ["Hello", "Hello2", "Hello3", "Hello4"]
I have tried this:

sum(map(str.split, sum([[k] if isinstance(k, str) else k for k in single_list1], [])), [])
However this will not work as the real list has spaces and this splits them into different list items too which I do not want.
I have tried a number of different functions in place of str.split however none worked.

Please help
That line is easy to read Doh
This approach is usually what i have used for this,can also trow in a yield from(new in Python 3.3) to make it a little cooler.
def flatten(seq):
    for item in seq:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

mylist = ["Hello", ["Hello2", "Hello3"], "Hello4"]
print(list(flatten(mylist)))
Output:
['Hello', 'Hello2', 'Hello3', 'Hello4']
Ok. I'll try it

It doesn't work. In my real code, the Listbox has some silly object code.
Unless I try this ...
Hang on
Non-Recursive implementation with a stack:

from collections import deque


def flatten(iterable):
    stack = deque(iterable)
    while stack:
        item = stack.popleft()
        if isinstance(item, list):
            stack.extendleft(item)
        else:
            yield item


mylist = ["Hello", ["Hello2", "Hello3"], "Hello4"]
flatten_list = list(flatten(mylist))
print(flatten_list)
Output:
['Hello', 'Hello3', 'Hello2', 'Hello4']
The isinstance check is the important part. If item is a list, it's added unpacked to the left side of the stack. The extendleft method of deque takes iterables.
I'll try that too. Thanks for the help everyone :)

It gave an error. :(

The class:
class SetCategory:
    def flatten(self, iterable):
        stack = deque(iterable)
        while stack:
            item = stack.popleft()
            if isinstance(item, list):
                stack.extendleft(item)
            else:
                yield item

    def updateNextBtn(self, evt):
        if self.itemslistDuplicate.curselection() == ():
            self.nextBtn.config(state = DISABLED)
        else:
            self.nextBtn.config(state = NORMAL)

    def SET_CATEGORY(self):
        global food_category_list
        global confectionery_category_list
        global dairy_category_list
        global fruit_veg_category_list
        global meat_fish_chicken_category_list
        global diy_category_list
        global other_category_list

        category_chosen = self.categories.get()
        selected = self.itemslistDuplicate.curselection()
        selected_items = [[self.itemslistDuplicate.get(i) for i in self.itemslistDuplicate.curselection()]]

        if category_chosen == "Food":
            for i in range(0, len(str(self.flatten(selected_items)))):
                food_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "Confectionery":
            for i in range(0, len(str(self.flatten(selected_items)))):
                confectionery_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "Dairy":
            for i in range(0, len(str(self.flatten(selected_items)))):
                dairy_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "Fruit & Vegetables":
            for i in range(0, len(str(self.flatten(selected_items)))):
                fruit_veg_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "Meat, Fish & Chicken":
            for i in range(0, len(str(self.flatten(selected_items)))):
                meat_fish_chicken_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "DIY":
            for i in range(0, len(str(self.flatten(selected_items)))):
                diy_category_list.append(self.flatten(selected_items[i]))
        elif category_chosen == "Other":
            for i in range(0, len(str(self.flatten(selected_items)))):
                other_category_list.append(self.flatten(selected_items[i]))

        print(fruit_veg_category_list)
        
        messagebox.showinfo("Category set", "The category has been set")
        self.category.destroy()

    def __init__(self):
        global itemslist

        self.categoryItems = []

        self.category = Tk()
        self.category.title("OrderLog - Set item category")
        self.category.attributes("-toolwindow", 1)
        self.category.attributes("-topmost", 1)
        self.category.geometry("300x450")

        Label(self.category, text = "Set item category", font = ("Helvetica", 23)).pack(padx = 30, pady = 30)

        self.categories = Combobox(self.category, state = "readonly", values = ("Food", "Confectionery", "Dairy", "Fruit & Vegetables", "Meat, Fish & Chicken", "DIY", "Other"))
        self.categories.current(0)
        self.categories.pack(pady = 20)

        Label(self.category, text = "Select items to place in this category").pack(pady = 20)

        self.itemslistDuplicate = Listbox(self.category, selectmode = "multiple")
        self.itemslistDuplicate.pack(pady = 20)

        for i in range(0, itemslist.size()):
            self.itemslistDuplicate.insert(i, itemslist.get(i))

        self.nextBtn = Button(self.category, text = "Set category", width = window.winfo_screenwidth(), state = DISABLED, command = self.SET_CATEGORY)
        self.nextBtn.pack()

        self.category.bind("<<ListboxSelect>>", self.updateNextBtn)
The error
Error:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\joshu\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__ return self.func(*args) File "C:/Users/joshu/Downloads/OrderLog.py", line 494, in SET_CATEGORY food_category_list.append(self.flatten(selected_items[i])) IndexError: list index out of range

And the viewing category (don't know if this shows an error or not):
class ViewCategory:
    def flatten(self, iterable):
        stack = deque(iterable)
        while stack:
            item = stack.popleft()
            if isinstance(item, list):
                stack.extendleft(item)
            else:
                yield item

    def viewCategoryItems(self):
        global food_category_list
        global confectionery_category_list
        global dairy_category_list
        global fruit_veg_category_list
        global meat_fish_chicken_category_list
        global diy_category_list
        global other_category_list

        self.sel_category.destroy()

        self.categoryViewer = Tk()
        self.categoryViewer.title("View category items")
        self.categoryViewer.attributes("-toolwindow", 1)
        self.categoryViewer.resizable(0, 0)

        category_items = Listbox(self.categoryViewer)
        category_items.pack()

        flat_food_category_list = list(self.flatten(food_category_list))
        flat_confectionery_category_list = list(self.flatten(confectionery_category_list))
        flat_dairy_category_list = list(self.flatten(dairy_category_list))
        flat_fruit_veg_category_list = list(self.flatten(fruit_veg_category_list))
        flat_meat_fish_chicken_category_list = list(self.flatten(meat_fish_chicken_category_list))
        flat_diy_category_list = list(self.flatten(diy_category_list))
        flat_other_category_list = list(self.flatten(other_category_list))

        lastItem = self.radioButtonList[-1]

        if lastItem == "0":
            for i in range(0, len(flat_food_category_list)):
                category_items.insert(i, str(flat_food_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "1":
            for i in range(0, len(flat_confectionery_category_list)):
                category_items.insert(i, str(flat_confectionery_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "2":
            for i in range(0, len(flat_dairy_category_list)):
                category_items.insert(i, str(flat_dairy_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "3":
            for i in range(0, len(flat_fruit_veg_category_list)):
                category_items.insert(i, str(flat_fruit_veg_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "4":
            for i in range(0, len(flat_meat_fish_chicken_category_list)):
                category_items.insert(i, str(flat_meat_fish_chicken_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "5":
            for i in range(0, len(flat_diy_category_list)):
                category_items.insert(i, str(flat_diy_category_list[i]).replace("{", "").replace("}", ""))
        elif lastItem == "6":
            for i in range(0, len(flat_other_category_list)):
                category_items.insert(i, str(flat_other_category_list[i]).replace("{", "").replace("}", ""))

        self.radioButtonList.clear()

    def foodAppend(self):
        self.radioButtonList.append("0")

    def confectioneryAppend(self):
        self.radioButtonList.append("1")

    def dairyAppend(self):
        self.radioButtonList.append("2")

    def fruitVegAppend(self):
        self.radioButtonList.append("3")

    def meatFishChickenAppend(self):
        self.radioButtonList.append("4")

    def diyAppend(self):
        self.radioButtonList.append("5")

    def otherAppend(self):
        self.radioButtonList.append("6")

    def __init__(self):
        self.tkVariable = IntVar()
        self.radioButtonList = []

        self.sel_category = Tk()
        self.sel_category.title("Select category to view")
        self.sel_category.attributes("-toolwindow", 1)
        self.sel_category.attributes("-topmost", 1)
        self.sel_category.geometry("300x600")

        Label(self.sel_category, text = "Select item category to view", font = ("Helvetica", 23)).pack(padx = 30, pady = 30)

        self.foodOption = Radiobutton(self.sel_category, text = "Food", variable = self.tkVariable, value = 1, command = self.foodAppend)
        self.foodOption.pack()

        self.confectioneryOption = Radiobutton(self.sel_category, text = "Confectionery", variable = self.tkVariable, value = 2, command = self.confectioneryAppend)
        self.confectioneryOption.pack()

        self.dairyOption = Radiobutton(self.sel_category, text = "Dairy", variable = self.tkVariable, value = 3, command = self.dairyAppend)
        self.dairyOption.pack()

        self.fruitVegOption = Radiobutton(self.sel_category, text = "Fruit & Vegetables", variable = self.tkVariable, value = 4, command = self.fruitVegAppend)
        self.fruitVegOption.pack()

        self.meatFishChickenOption = Radiobutton(self.sel_category, text = "Meat, Fish & Chicken", variable = self.tkVariable, value = 5, command = self.meatFishChickenAppend)
        self.meatFishChickenOption.pack()

        self.diyOption = Radiobutton(self.sel_category, text = "DIY", variable = self.tkVariable, value = 6, command = self.diyAppend)
        self.diyOption.pack()

        self.otherOption = Radiobutton(self.sel_category, text = "Other", variable = self.tkVariable, value = 7, command = self.otherAppend)
        self.otherOption.pack()

        Label(self.sel_category).pack()

        self.viewCategoryBtn = Button(self.sel_category, text = "View category items", width = 65, state = NORMAL, command = self.viewCategoryItems)
        self.viewCategoryBtn.pack()
Toolz is a very useful library and its concat function may be useful.
concat? i don't want to concatenate a string.
import itertools
origin_list = here you enter 
flat_list = list(itertools.chain.from_iterable(origin_list))                 
print(flat_list)
Yeah. I'll try all of these if I need to

Thanks a lot everyone! My program is fixed!