Skip to main content
added 118 characters in body
Source Link
kyrill
  • 1.6k
  • 11
  • 24

No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.

In terms of efficiency (or time / space complexity), your code is \$O(n^3)\$ in time and \$O(1)\$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be \$O(n^2)\$ in time. The most time-efficient solution is \$O(n)\$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is \$O(n)\$ -- inferior to your original approach.

If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.


from collections import defaultdict

def tuples_to_neighbors_dict(tuples):
  """
  Covert `tuples` to a dict mapping each point to a list of its neighbors.
  """
  neighbors = defaultdict(list)

  for (a,b) in tuples:
    neighbors[a].append(b)
    neighbors[b].append(a)

  return neighbors

def tuples_to_order(tuples, start=0):
  """
  Covert `tuples` to a list of points.
  """
  neighbors = tuples_to_neighbors_dict(tuples)
  order = []

  prev = None
  current = start

  while current != start or prev is None:
    # add the current value to the list
    order.append(current)

    # move to the next -- pick the neighbor which we haven't visited yet
    neigh = neighbors[current]
    new = neigh[1] if neigh[0] == prev else neigh[0]
    prev = current
    current = new
  
  return order

EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁

No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.

In terms of efficiency (or time / space complexity), your code is \$O(n^3)\$ in time and \$O(1)\$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be \$O(n^2)\$ in time. The most time-efficient solution is \$O(n)\$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is \$O(n)\$ -- inferior to your original approach.

If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.


from collections import defaultdict

def tuples_to_neighbors_dict(tuples):
  """
  Covert `tuples` to a dict mapping each point to a list of its neighbors.
  """
  neighbors = defaultdict(list)

  for (a,b) in tuples:
    neighbors[a].append(b)
    neighbors[b].append(a)

  return neighbors

def tuples_to_order(tuples, start=0):
  """
  Covert `tuples` to a list of points.
  """
  neighbors = tuples_to_neighbors_dict(tuples)
  order = []

  prev = None
  current = start

  while current != start or prev is None:
    # add the current value to the list
    order.append(current)

    # move to the next -- pick the neighbor which we haven't visited yet
    neigh = neighbors[current]
    new = neigh[1] if neigh[0] == prev else neigh[0]
    prev = current
    current = new
  
  return order

No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.

In terms of efficiency (or time / space complexity), your code is \$O(n^3)\$ in time and \$O(1)\$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be \$O(n^2)\$ in time. The most time-efficient solution is \$O(n)\$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is \$O(n)\$ -- inferior to your original approach.

If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.


from collections import defaultdict

def tuples_to_neighbors_dict(tuples):
  """
  Covert `tuples` to a dict mapping each point to a list of its neighbors.
  """
  neighbors = defaultdict(list)

  for (a,b) in tuples:
    neighbors[a].append(b)
    neighbors[b].append(a)

  return neighbors

def tuples_to_order(tuples, start=0):
  """
  Covert `tuples` to a list of points.
  """
  neighbors = tuples_to_neighbors_dict(tuples)
  order = []

  prev = None
  current = start

  while current != start or prev is None:
    # add the current value to the list
    order.append(current)

    # move to the next -- pick the neighbor which we haven't visited yet
    neigh = neighbors[current]
    new = neigh[1] if neigh[0] == prev else neigh[0]
    prev = current
    current = new
  
  return order

EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁

Source Link
kyrill
  • 1.6k
  • 11
  • 24

No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.

In terms of efficiency (or time / space complexity), your code is \$O(n^3)\$ in time and \$O(1)\$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be \$O(n^2)\$ in time. The most time-efficient solution is \$O(n)\$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is \$O(n)\$ -- inferior to your original approach.

If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.


from collections import defaultdict

def tuples_to_neighbors_dict(tuples):
  """
  Covert `tuples` to a dict mapping each point to a list of its neighbors.
  """
  neighbors = defaultdict(list)

  for (a,b) in tuples:
    neighbors[a].append(b)
    neighbors[b].append(a)

  return neighbors

def tuples_to_order(tuples, start=0):
  """
  Covert `tuples` to a list of points.
  """
  neighbors = tuples_to_neighbors_dict(tuples)
  order = []

  prev = None
  current = start

  while current != start or prev is None:
    # add the current value to the list
    order.append(current)

    # move to the next -- pick the neighbor which we haven't visited yet
    neigh = neighbors[current]
    new = neigh[1] if neigh[0] == prev else neigh[0]
    prev = current
    current = new
  
  return order