// get all undirected edges and all unique undirected edges: the latter
// throws away any parallel edges (including those in self-loops)
all_edges = G.to_undirected(reciprocal=False).edges(keys=False)
all_unique_edges = set(all_edges)
// get all edges (including parallel edges) that are not self-loops
non_self_loop_edges = [e for e in all_edges if e[0] != e[1]]
// get a single copy of each self-loop edge (ie, if it"s bi-directional, we
// ignore the parallel edge going reverse direction to keep only one copy)
set_non_self_loop_edges = set(non_self_loop_edges)
self_loop_edges = [e for e in all_unique_edges if e not in set_non_self_loop_edges]
// final list contains all unique edges including each parallel edge unless
// the parallel edge is a self-loop, in which case don"t double-count it
After Change
// get one copy of each self-loop edge, because bi-directional self-loops
// appear twice in the undirected graph (u,v,0 and u,v,1 where u=v), but
// one-way self-loops will appear only once
Gu = G.to_undirected(reciprocal=False, as_view=True)
self_loop_edges = set(nx.selfloop_edges(Gu))
// get all non-self-loop undirected edges, including parallel edges
non_self_loop_edges = [e for e in Gu.edges(keys=False) if e not in self_loop_edges]
// make list of all unique edges including each parallel edge unless the
// parallel edge is a self-loop, in which case we don"t double-count it