Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Flatten list sublists
#1
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
Reply
#2
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']
Reply
#3
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
Reply
#4
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.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#5
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()
Reply
#6
Toolz is a very useful library and its concat function may be useful.
Reply
#7
concat? i don't want to concatenate a string.
Reply
#8
import itertools
origin_list = here you enter 
flat_list = list(itertools.chain.from_iterable(origin_list))                 
print(flat_list)
Reply
#9
Yeah. I'll try all of these if I need to

Thanks a lot everyone! My program is fixed!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  List of lists - merge sublists with common elements medatib531 1 3,354 May-09-2021, 07:49 AM
Last Post: Gribouillis
  Take first Elements of sublists quest 2 2,167 Apr-26-2021, 11:32 AM
Last Post: buran
  Converting list elements and sublists from int to str iMuny 5 4,517 Mar-10-2019, 09:05 PM
Last Post: iMuny
  Help to flatten list of nested dictionaries shawbapmp 4 5,623 Feb-25-2019, 10:18 PM
Last Post: shawbapmp
  help with flatten nested list Arch2030 6 3,273 Jan-24-2019, 04:50 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020