Given the following list of redirects
[
{
"old": "a",
"target": "b"
},
{
"old": "b",
"target": "c"
},
{
"old": "c",
"target": "d"
},
{
"old": "d",
"target": "a"
},
{
"old": "o",
"target": "n"
},
{
"old": "n",
"target": "b"
},
{
"old": "j",
"target": "x"
},
{
"old": "whatever",
"target": "something"
}
]
Here we can see that the first item "a" should redirect to "b". If we follow the list we can see the following pattern:
a -> b
b -> c
c -> d
d -> a
So we would end up with a circular reference since "a" would end up pointing to "d" and "d" points to "a".
What would be the most efficient way of finding the circular references?
I've come up with the following algorithm in C#
var items = JsonConvert.DeserializeObject<IEnumerable<Item>>(json)
.GroupBy(x => x.Old)
.Select(x => x.First())
.ToDictionary(x => x.Old, x => x.Target);
var circulars = new Dictionary<string, string>();
foreach (var item in items)
{
var target = item.Value;
while (items.ContainsKey(target))
{
target = items[target];
if (target.Equals(item.Key))
{
circulars.Add(target, item.Value);
break;
}
}
}
This will give me a list containing 4 items looking like this:
[
{
"old": "a",
"target": "b"
},
{
"old": "b",
"target": "c"
},
{
"old": "c",
"target": "d"
},
{
"old": "d",
"target": "a"
}
]
But im only interested in telling the user something like
"Hey you can't do that, It will be a circular reference because of "a" points to "b" which points to "c" which points to "d" which points to "a"
So, do you guys have any suggestions? Im sure that some other(better) algorithms exists for doing this... :)
> (A list of circular, where each "circular" is a List of the nodes included in that circular).