input: Write a python function to solve the knapsack problem for a list of items with given weights and values, ensuring the maximum value without exceeding a specified weight limit.
  assert knapsack([{"name": "pencil", "weight": 5, "value": 10}, {"name": "eraser", "weight": 3, "value": 5}, {"name": "book", "weight": 8, "value": 15}, {"name": "notebook", "weight": 2, "value": 3}], 8) == ["eraser", "book"]
  assert knapsack([{"name": "pen", "weight": 2, "value": 3}, {"name": "ruler", "weight": 3, "value": 4}, {"name": "scissors", "weight": 4, "value": 5}, {"name": "glue", "weight": 1, "value": 1}], 5) == ["ruler", "scissors"]
  assert knapsack([{"name": "apple", "weight": 1, "value": 1}, {"name": "banana", "weight": 2, "value": 2}, {"name": "cherry", "weight": 1, "value": 2}, {"name": "date", "weight": 2, "value": 3}], 3) == ["cherry", "date"]
output: def knapsack(items, max_weight):
      n = len(items)
      dp = [[0] * (max_weight + 1) for _ in range(n + 1)]
  
      for i in range(1, n + 1):
          for w in range(1, max_weight + 1):
              if items[i - 1]["weight"] <= w:
                  dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - items[i - 1]["weight"]] + items[i - 1]["value"])
              else:
                  dp[i][w] = dp[i - 1][w]
  
      w = max_weight
      selected_items = []
      for i in range(n, 0, -1):
          if dp[i][w] != dp[i - 1][w]:
              selected_items.append(items[i - 1]["name"])
              w -= items[i - 1]["weight"]
  
      return selected_items[::-1]