Checking all possible permutations of an array - c#

i'm creating a program which requires to check every possible permutation. let's say we have 1,2,3 the program will work just fine and show me all the possible ones : 1,3,2 2,1,3 2,3,1 3,1,2 and 3,2,1 however i also want it to be able to try such combinations
1,1,1
2,2,2
1,2,2
3,3,2
i.e include absolutely every possible combination.. Here's my code :
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
{
// More efficient to have a variable instead of accessing a property
var count = elements.Length;
// Indicates whether this is the last lexicographic permutation
var done = true;
// Go through the array from last to first
for (var i = count - 1; i > 0; i--)
{
var curr = elements[i];
// Check if the current element is less than the one before it
if (curr.CompareTo(elements[i - 1]) < 0)
{
continue;
}
// An element bigger than the one before it has been found,
// so this isn't the last lexicographic permutation.
done = false;
// Save the previous (bigger) element in a variable for more efficiency.
var prev = elements[i - 1];
// Have a variable to hold the index of the element to swap
// with the previous element (the to-swap element would be
// the smallest element that comes after the previous element
// and is bigger than the previous element), initializing it
// as the current index of the current item (curr).
var currIndex = i;
// Go through the array from the element after the current one to last
for (var j = i + 1; j < count; j++)
{
// Save into variable for more efficiency
var tmp = elements[j];
// Check if tmp suits the "next swap" conditions:
// Smallest, but bigger than the "prev" element
if (tmp.CompareTo(curr) < 0 && tmp.CompareTo(prev) > 0)
{
curr = tmp;
currIndex = j;
}
}
// Swap the "prev" with the new "curr" (the swap-with element)
elements[currIndex] = prev;
elements[i - 1] = curr;
// Reverse the order of the tail, in order to reset it's lexicographic order
for (var j = count - 1; j > i; j--, i++)
{
var tmp = elements[j];
elements[j] = elements[i];
elements[i] = tmp;
}
// Break since we have got the next permutation
// The reason to have all the logic inside the loop is
// to prevent the need of an extra variable indicating "i" when
// the next needed swap is found (moving "i" outside the loop is a
// bad practice, and isn't very readable, so I preferred not doing
// that as well).
break;
}
// Return whether this has been the last lexicographic permutation.
return done;
}
This is a simple example of how i use it
var arr = new[] {0, 1, 2,};
var conditions = new[] {true, false, true};
int count = 0;
while (!NextPermutation(arr))
{
List<bool> tempConditions = new List<bool>();
for (int i = 0; i < arr.Length; i++)
{
tempConditions.Add(conditions[arr[i]]);
Console.Write(tempConditions[i] + " ");
}
count++;
Console.WriteLine();
}
Console.WriteLine("count : {0}", count);

You can do this with a method that returns IEnumerable<IEnumerable<T>> like so:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public static class Program
{
public static void Main()
{
string[] test = {"A", "B", "C", "D"};
foreach (var perm in PermuteWithRepeats(test))
Console.WriteLine(string.Join(" ", perm));
}
public static IEnumerable<IEnumerable<T>> PermuteWithRepeats<T>(IEnumerable<T> sequence)
{
return permuteWithRepeats(sequence, sequence.Count());
}
private static IEnumerable<IEnumerable<T>> permuteWithRepeats<T>(IEnumerable<T> sequence, int count)
{
if (count == 0)
{
yield return Enumerable.Empty<T>();
}
else
{
foreach (T startingElement in sequence)
{
IEnumerable<T> remainingItems = sequence;
foreach (IEnumerable<T> permutationOfRemainder in permuteWithRepeats(remainingItems, count - 1))
yield return new[]{startingElement}.Concat(permutationOfRemainder);
}
}
}
}
}

1,1,2 2,2,2 and such aren't permutations - they are variations. There will be count ^ count of them
You can generate them like this:
// you can do precise powering if needed
double number_of_variations = Math.Pow(count, count);
T[] result = new T[count];
for (int i = 0; i < number_of_variations; ++i) {
int x = i;
for (int j = 0; j < count; ++j) {
result[j] = elements[x % count];
x /= count;
}
// do something with one of results
}

Related

How to delete an element of an array?

I know this topic name is similar to another topic but that topic doesn't have the answers i wanted, so...
1st Question:
Let me say i have an array of:
string[] test = new string[5];
for(int x = 0; x <= test.Length - 1; x++)
{
test[x] = "#" + (x + 1) + " element";
Console.WriteLine(test[x]);
}
/*
output:
#1 element
#2 element
#3 element
#4 element
#5 element
*/
and say i wanted to remove "#4 element" from the string array, so that it instead outputs:
/*
output:
#1 element
#2 element
#3 element
#5 element
*/
how do i do that?
[PS:]The Answer i'm looking for is something that's easy to understand for a beginner.
If you want to delete at particular index you can do as :
int[] numbers = { 1,2,3,4,5};
List<int> tmp = new List<int>(numbers);
tmp.RemoveAt(4);
numbers = tmp.ToArray();
But In your case since you are just expecting the element to be invisible and having the array length same :
string[] test = new string[5];
for(int x = 0; x <= test.Length - 1; x++)
{
if(x!=3){
test[x] = "#" + (x + 1) + " element";
Console.WriteLine(test[x]);}
}
You cant just delete an Element from an array, you only can set it to "" for example.
Use List<string> instead.
1st Ans:
You can use list or if you dont want to use list use Linq but it will create a different memory location for array and will store elements there(I suppose).
You can implement linq on your array as below:
test = test.Where(x => !x.Equals("#4 element")).ToArray();
//Print test Now
and now test array does not have "#4 element".
2nd Ans
Instead of Console.WriteLine use Console.Write .
Use List<string> rather than an array.
Use list.RemoveAt(3) to remove the forth element (elements start at 0)
So you might end up with something like the following in order to achieve you desired output:
var test = new List<string>();
for (var x = 1; x <= 5; x++)
{
test.Add(String.Format("#{0} element", x));
}
Console.WriteLine(String.Join(" ", test);
test.RemoveAt(3);
Console.WriteLine(String.Join(" ", test);
Which will give you your desired output of:
#1 element #2 element #3 element #4 element #5 element
#1 element #2 element #3 element #5 element
For your edit. While flushing your o/p just do not flush the outdated element. Using some conditional operator.
Eg: 1. If you want to remove on the basis of array valve then use
string[] test = new string[5];
for(int x = 0; x <= test.Length - 1; x++)
{
test[x] = "#" + (x + 1) + " element";
If (test[x] == "Desired value which you dont want to show")
Console.WriteLine(test[x]);
}
If you want to remove on the basis of array position then use
string[] test = new string[5];
for(int x = 0; x <= test.Length - 1; x++)
{
test[x] = "#" + (x + 1) + " element";
If (x == "Desired index which you dont want to show")
Console.WriteLine(test[x]);
}
While what the others wrote is correct, sometimes you have an array, and you don't want to have a List<>...
public static void Main()
{
string[] test = new string[5];
for(int x = 0; x < test.Length; x++)
{
test[x] = "#" + (x + 1) + " element";
Console.WriteLine(test[x]);
}
Console.WriteLine();
RemoveAt(ref test, 3);
// Or RemoveRange(ref test, 3, 1);
for(int x = 0; x < test.Length; x++)
{
Console.WriteLine(test[x]);
}
}
public static void RemoveAt<T>(ref T[] array, int index)
{
RemoveRange(ref array, index, 1);
}
public static void RemoveRange<T>(ref T[] array, int start, int count)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (start < 0 || start > array.Length)
{
throw new ArgumentOutOfRangeException("start");
}
if (count < 0 || start + count > array.Length)
{
throw new ArgumentOutOfRangeException("count");
}
if (count == 0)
{
return;
}
T[] orig = array;
array = new T[orig.Length - count];
Array.Copy(orig, 0, array, 0, start);
Array.Copy(orig, start + count, array, start, array.Length - start);
}
Two simple methods to remove elements of an array (RemoveAt and RemoveRange), with full example of use.
Arrays have fixed size, so if you want add or remove element from them you need to deal with resizing. Therefore in C# it is recommended to use Lists instead (they deal with it themselves).Here is nice post about Arrays vs Lists.
But if you really want to do it with Array or have a reason for that, you could do it this way:
class Program
{
static void Main(string[] args)
{
int[] myArray = { 1, 2, 3, 4, 5 };
//destination array
int[] newArray = new int[myArray.Length-1];
//index of the element you want to delete
var index = 3;
//get and copy first 3 elements
Array.Copy(myArray, newArray, index);
//get and copy remaining elements without the 4th
Array.Copy(myArray, index + 1, newArray, index, myArray.Length-(index+1));
//Output newArray
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < newArray.Length; i++)
{
sb.Append(String.Format("#{0} {1}", i + 1, newArray[i]));
if (!(i == newArray.Length - 1))
{
sb.Append(", ");
}
}
Console.Write(sb.ToString());
Console.ReadLine();
}
See My solution... let me know if does helps...
class Program
{
// this program will work only if you have distinct elements in your array
static void Main(string[] args)
{
string[] test = new string[5];
for (int x = 0; x <= test.Length - 1; x++)
{
test[x] = "#" + (x + 1) + " element";
Console.WriteLine(test[x]);
}
Console.ReadKey();
Program p = new Program();
test = p.DeleteKey(test, "#3 element"); // pass the array and record to be deleted
for (int x = 0; x <= test.Length - 1; x++)
{
Console.WriteLine(test[x]);
}
Console.ReadKey();
}
public string[] DeleteKey(string[] arr, string str)
{
int keyIndex = 0;
if (arr.Contains(str))
{
for (int i = 0; i < arr.Length - 1; i++)
{
if (arr[i] == str)
{
keyIndex = i; // get the index position of string key
break; // break if index found, no need to search items for further
}
}
for (int i = keyIndex; i <= arr.Length - 2; i++)
{
arr[i] = arr[i+1]; // swap next elements till end of the array
}
arr[arr.Length - 1] = null; // set last element to null
return arr; // return array
}
else
{
return null;
}
}
}

Order an array in a specific order

I have this array of integers:-
int[] numbers = new int[] { 10, 20, 30, 40 };
I am trying to create an array which will have first element, last element, second element, second-last element and so on..
So, my resulting output will be:-
int[] result = {10,40,20,30};
This was my approach, in one loop start from first and go till the middle & in second loop start from last and get to the middle and select items accordingly, but I totally messed it up. Here is my attempted code:-
private static IEnumerable<int> OrderedArray(int[] numbers)
{
bool takeFirst = true;
if (takeFirst)
{
takeFirst = false;
for (int i = 0; i < numbers.Length / 2; i++)
{
yield return numbers[i];
}
}
else
{
takeFirst = true;
for (int j = numbers.Length; j < numbers.Length / 2; j--)
{
yield return numbers[j];
}
}
}
Need Help.
You might try this:
int[] result = numbers.Zip(numbers.Reverse(), (n1,n2) => new[] {n1, n2})
.SelectMany(x =>x)
.Take(numbers.Length)
.ToArray();
Explanation: This approach basically pairs up the elements of the original collection with the elements of its reverse ordered collection (using Zip). So you get a collection of pairs like [first, last], [second, second from last], etc.
It then flattens those collection of pairs into a single collection (using SelectMany). So the collection becomes [first, last, second, second from last,...].
Finally, we limit the number of elements to the length of the original array (n). Since we are iterating through twice as many elements (normal and reverse), it works out that iterating through n elements allow us to stop in the middle of the collection.
As a different approach, this is a modification on your existing method:
private static IEnumerable<int> OrderedArray(int[] numbers)
{
var count = (numbers.Length + 1) / 2;
for (int i = 0; i < count; i++)
{
yield return numbers[i];
int reverseIdx = numbers.Length - 1 - i;
if(i != reverseIdx)
yield return numbers[reverseIdx];
}
}
ok,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var length = source.Count;
var limit = length / 2;
for (var i = 0; i < limit; i++)
{
yield return source[i];
yield return source[length - i - 1];
}
if (length % 2 > 0)
{
yield return source[limit];
}
}
}
Which you could use like this,
var result = numbers.EndToEnd().ToArray();
more optimally,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var c = source.Count;
for (int i = 0, f = 0, l = c - 1; i < c; i++, f++, l--)
{
yield return source[f];
if (++i == c)
{
break;
}
yield return source[l];
}
}
}
no divide or modulus required.
With a simple for;
int len = numbers.Length;
int[] result = new int[len];
for (int i = 0, f = 0, l = len - 1; i < len; f++, l--)
{
result[i++] = numbers[f];
if (f != l)
result[i++] = numbers[l];
}
Based on Selman22's now deleted answer:
int[] numbers = new int[] { 10, 20, 30, 40 };
int[] result = numbers
.Select((x,idx) => idx % 2 == 0
? numbers[idx/2]
: numbers[numbers.Length - 1 -idx/2])
.ToArray();
result.Dump();
(The last line is LinqPad's way of outputting the results)
Or in less LINQy form as suggested by Jeppe Stig Nielsen
var result = new int[numbers.Length];
for (var idx = 0; idx < result.Length; idx++) {
result[idx] = idx % 2 == 0 ? numbers[idx/2] : numbers[numbers.Length - 1 -idx/2];
}
The principle is that you have two sequences, one for even elements (in the result) and one for odd. The even numbers count the first half of the array and the odds count the second half from the back.
The only modification to Selman's code is adding the /2 to the indexes to keep it counting one by one in the right half while the output index (which is what idx basically is in this case) counts on.
Came up with this
static void Main(string[] args)
{
List<int> numbers = new List<int>() { 10, 20, 30, 40, 50, 60, 70};
List<int> numbers2 = new List<int>();
int counter1 = 0;
int counter2 = numbers.Count - 1;
int remainder = numbers.Count % 2 == 0 ? 1: 0;
while (counter1-1 < counter2)
{
if (counter1 + counter2 % 2 == remainder)
{
numbers2.Add(numbers[counter1]);
counter1++;
}
else
{
numbers2.Add(numbers[counter2]);
counter2--;
}
}
string s = "";
for(int a = 0; a< numbers2.Count;a++)
s+=numbers2[a] + " ";
Console.Write(s);
Console.ReadLine();
}
This late answer steals a lot from the existing answers!
The idea is to allocate the entire result array at once (since its length is known). Then fill out all even-indexed members first, from one end of source. And finally fill out odd-numbered entries from the back end of source.
public static TElement[] EndToEnd<TElement>(this IReadOnlyList<TElement> source)
{
var count = source.Count;
var result = new TElement[count];
for (var i = 0; i < (count + 1) / 2; i++)
result[2 * i] = source[i];
for (var i = 1; i <= count / 2; i++)
result[2 * i - 1] = source[count - i];
return result;
}
Came up with this
public int[] OrderedArray(int[] numbers)
{
int[] final = new int[numbers.Length];
var limit=numbers.Length;
int last = numbers.Length - 1;
var finalCounter = 0;
for (int i = 0; finalCounter < numbers.Length; i++)
{
final[finalCounter] = numbers[i];
final[((finalCounter + 1) >= limit ? limit - 1 : (finalCounter + 1))] = numbers[last];
finalCounter += 2;
last--;
}
return final;
}

c# permutation without repetition when order is important [duplicate]

I have a list of Offers, from which I want to create "chains" (e.g. permutations) with limited chain lengths.
I've gotten as far as creating the permutations using the Kw.Combinatorics project.
However, the default behavior creates permutations in the length of the list count. I'm not sure how to limit the chain lengths to 'n'.
Here's my current code:
private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength)
{
List<List<Offers>> response = new List<List<Offers>>();
foreach (var row in new Permutation(list.Count).GetRows())
{
List<Offers> innerList = new List<Offers>();
foreach (var mix in Permutation.Permute(row, list))
{
innerList.Add(mix);
}
response.Add(innerList);
innerList = new List<Offers>();
}
return response;
}
Implemented by:
List<List<AdServer.Offers>> lst = GetPerms(offers, 2);
I'm not locked in KWCombinatorics if someone has a better solution to offer.
Here's another implementation which I think should be faster than the accepted answer (and it's definitely less code).
public static IEnumerable<IEnumerable<T>> GetVariationsWithoutDuplicates<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items.Distinct()
from permutation in GetVariationsWithoutDuplicates(items.Where(i => !EqualityComparer<T>.Default.Equals(i, item)).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<IEnumerable<T>> GetVariations<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items
from permutation in GetVariations(Remove(item, items).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<T> Prepend<T>(T first, IEnumerable<T> rest)
{
yield return first;
foreach (var item in rest) yield return item;
}
public static IEnumerable<T> Remove<T>(T item, IEnumerable<T> from)
{
var isRemoved = false;
foreach (var i in from)
{
if (!EqualityComparer<T>.Default.Equals(item, i) || isRemoved) yield return i;
else isRemoved = true;
}
}
On my 3.1 GHz Core 2 Duo, I tested with this:
public static void Test(Func<IList<int>, int, IEnumerable<IEnumerable<int>>> getVariations)
{
var max = 11;
var timer = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i < max; ++i)
for (int j = 1; j < i; ++j)
getVariations(MakeList(i), j).Count();
timer.Stop();
Console.WriteLine("{0,40}{1} ms", getVariations.Method.Name, timer.ElapsedMilliseconds);
}
// Make a list that repeats to guarantee we have duplicates
public static IList<int> MakeList(int size)
{
return Enumerable.Range(0, size/2).Concat(Enumerable.Range(0, size - size/2)).ToList();
}
Unoptimized
GetVariations 11894 ms
GetVariationsWithoutDuplicates 9 ms
OtherAnswerGetVariations 22485 ms
OtherAnswerGetVariationsWithDuplicates 243415 ms
With compiler optimizations
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms
You're not looking for a permutation, but for a variation. Here is a possible algorithm. I prefer iterator methods for functions that can potentially return very many elements. This way, the caller can decide if he really needs all elements:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
var variationElements = new HashSet<T>(); //for duplicate detection
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
var valid = true;
for (int i = 0; i < length; ++i)
{
var element = offers[startIndices[i]];
if (variationElements.Contains(element))
{
valid = false;
break;
}
variation.Add(element);
variationElements.Add(element);
}
if (valid)
yield return variation;
//Count up the indices
startIndices[length - 1]++;
for (int i = length - 1; i > 0; --i)
{
if (startIndices[i] >= offers.Count)
{
startIndices[i] = 0;
startIndices[i - 1]++;
}
else
break;
}
variationElements.Clear();
}
}
The idea for this algorithm is to use a number in offers.Count base. For three offers, all digits are in the range 0-2. We then basically increment this number step by step and return the offers that reside at the specified indices. If you want to allow duplicates, you can remove the check and the HashSet<T>.
Update
Here is an optimized variant that does the duplicate check on the index level. In my tests it is a lot faster than the previous variant:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
for (int i = 0; i < length; ++i)
startIndices[i] = i;
var indices = new HashSet<int>(); // for duplicate check
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
for (int i = 0; i < length; ++i)
{
variation.Add(offers[startIndices[i]]);
}
yield return variation;
//Count up the indices
AddOne(startIndices, length - 1, offers.Count - 1);
//duplicate check
var check = true;
while (check)
{
indices.Clear();
for (int i = 0; i <= length; ++i)
{
if (i == length)
{
check = false;
break;
}
if (indices.Contains(startIndices[i]))
{
var unchangedUpTo = AddOne(startIndices, i, offers.Count - 1);
indices.Clear();
for (int j = 0; j <= unchangedUpTo; ++j )
{
indices.Add(startIndices[j]);
}
int nextIndex = 0;
for(int j = unchangedUpTo + 1; j < length; ++j)
{
while (indices.Contains(nextIndex))
nextIndex++;
startIndices[j] = nextIndex++;
}
break;
}
indices.Add(startIndices[i]);
}
}
}
}
int AddOne(int[] indices, int position, int maxElement)
{
//returns the index of the last element that has not been changed
indices[position]++;
for (int i = position; i > 0; --i)
{
if (indices[i] > maxElement)
{
indices[i] = 0;
indices[i - 1]++;
}
else
return i;
}
return 0;
}
If I got you correct here is what you need
this will create permutations based on the specified chain limit
public static List<List<T>> GetPerms<T>(List<T> list, int chainLimit)
{
if (list.Count() == 1)
return new List<List<T>> { list };
return list
.Select((outer, outerIndex) =>
GetPerms(list.Where((inner, innerIndex) => innerIndex != outerIndex).ToList(), chainLimit)
.Select(perms => (new List<T> { outer }).Union(perms).Take(chainLimit)))
.SelectMany<IEnumerable<IEnumerable<T>>, List<T>>(sub => sub.Select<IEnumerable<T>, List<T>>(s => s.ToList()))
.Distinct(new PermComparer<T>()).ToList();
}
class PermComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<T> obj)
{
return (int)obj.Average(o => o.GetHashCode());
}
}
and you'll call it like this
List<List<AdServer.Offers>> lst = GetPerms<AdServer.Offers>(offers, 2);
I made this function is pretty generic so you may use it for other purpose too
eg
List<string> list = new List<string>(new[] { "apple", "banana", "orange", "cherry" });
List<List<string>> perms = GetPerms<string>(list, 2);
result

Altering a remove method to take an element from an array and moving the last value in its place

As the title suggest, in C# I'm trying to alter this remove method to take the last item in an array and move it in place of the value that was removed. This way when you remove an element, it doesn't have to take each and every individual number and move it up a space.
Here's my current code:
public override void remove(ref T item)
{
if (next == 0)
{
}
else
{
//find value, if it exists
for (int i = 0; i < next; i++)
{
if (item.Equals(list[i]))
{
for (int j = i; j < next; j++) list[j] = list[j + 1];
next--;
break;
}
}
}
}
Any help at all would be appreciated.
Here's my code for inserting the values into the array.
{
UnorderedArrayList<int> u = new UnorderedArrayList<int>();
u.print();
int var = 5;
u.insert(ref var);
var = 12;
u.insert(ref var);
var = 2;
u.insert(ref var);
var = 29;
u.insert(ref var);
u.print();
var = 5;
u.remove(ref var);
u.print();
}
All you have to do is replace your inner loop with code that moves the last item, and then clears the last item:
public override void remove(ref T item)
{
// find value, if it exists
for (int i = 0; i < next; i++)
{
if (item.Equals(list[i]))
{
list[i] = list[next-1];
list[next-1] = default(T);
next--;
break;
}
}
}
There's no need to check for next == 0 at the beginning because the for condition will check it. If next == 0, then the loop won't make any iterations.
When the item is found, the code just moves the last item to replace the item at the found index. It then sets the last item to default(T) (which will be null for reference types). If you don't do that you end up with a memory leak: storing references to things that you thought you removed. It won't affect operation of the list, but it could cause you to use more memory than you intended.
For some LINQy goodness:
public static IEnumerable<T> ShuffleRemove<T>(this IEnumerable<T> enumerable, T item)
{
var count = enumerable.Count();
var last = enumerable.ElementAt(count - 1);
var found = false;
for (int i = 0; i < count - 1; i++)
{
var current = enumerable.ElementAt(i);
if (!found && item.Equals(current))
{
yield return last;
found = true;
}
else
{
yield return current;
}
}
yield break;
}
Usage:
var array = new int[] { 1, 2, 2, 3, 4, 5 };
array.ShuffleRemove(2); // returns: 1, 5, 2, 3, 4
If you need it to replace all of the twos with 5, remove all the found terms.

What is the best way to route paths in a large grid?

I'm working on an algorithm to find a set of non intersected paths in a grid for a
given pairs of points..
Like this for these pairs:
(9,4) and (12,13)
The output should be something like this:
9,10,11,7,3,4
13,14,15,16,12
and print "Blocked" if it can't route all paths
First I searched for an already made algorithm to find all simple paths between 2
points in a graph or a grid. and I found this one by #Casey Watson and #svick here..
It works really well but for small graphs only.
I converted it to C#.NET and enhanced it a little bit to be able to find paths of
maximum length X. and build on it my total algorithm.
The one I built works fine in small graphs..
Here is routes 9 pairs in a 8x8 grid..
but it takes a huge time in larger ones like the 16x16 or even the final one I intended to do which is a 3D model of 16x16x2
Like this
The algorithm was developed to be a depth first search RECURSIVE algorithm, but it
took a huge time to return value to the user. so I decided to convert it to loops instead of the recursive calls so that I can benefit from yield return feature in .NET
but still it didn't help any better.
The loops version of the algorithm find a route for a pair of points in less than a second but the recursive one took more than 90 seconds.
when I tried with 2 pairs, the loops version took around 342 seconds but the recursive one took around 200..
So I can't know which is faster..!? the recursive or the loops one..
I really want to know the best way to do this..
Note : the first digit in the number of the node determine the layer (Starts at 1)..
Here is the code
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace AlgorithmTest
{
struct Connection
{
public int FirstNode;
public int SecondNode;
public Connection(int N1,int N2)
{
FirstNode = N1;
SecondNode = N2;
}
}
enum Algorithm
{ Recursion, Loops }
public class Search
{
private const int MAX = 15;
private const int Width = 16;
private const int Length = 16;
private const int Height = 2;
private static void Main(string[] args)
{
var graph = new Graph();
var str = new int[Height,Length, Width];
var level = ((int)Math.Pow(10, (Length * Width).ToString().Length) >= 100) ? (int)Math.Pow(10, (Length * Width).ToString().Length) : 100;
for (var i = 0; i < Height; i++)
{
int num = 0;
for (var j = 0; j < Length; j++)
for (var k = 0; k < Width; k++)
{
str[i, j, k] = ++num + level;
}
level += level;
}
for (var i = 0; i < Height; i++)
{
for (var j = 0; j < Length; j++)
{
for (var k = 0; k < Width; k++)
{
if (i < Height - 1) graph.addEdge(str[i, j, k], str[i + 1, j, k]);
if (i > 0) graph.addEdge(str[i, j, k], str[i - 1, j, k]);
if (k < Width - 1) graph.addEdge(str[i, j, k], str[i, j, k + 1]);
if (k > 0) graph.addEdge(str[i, j, k], str[i, j, k - 1]);
if (j < Length - 1) graph.addEdge(str[i, j, k], str[i, j + 1, k]);
if (j > 0) graph.addEdge(str[i, j, k], str[i, j - 1, k]);
}
}
}
var wt = new Stopwatch();
wt.Start();
var connectedNodes = new List<Connection>()
{
new Connection(1030, 1005),
// new Connection(1002, 1044),
// new Connection(1015, 1064),
// new Connection(1041, 1038),
// new Connection(1009, 1027),
// new Connection(1025, 1018),
// new Connection(1037, 1054),
// new Connection(1049, 1060),
// new Connection(1008, 1031),
// new Connection(1001, 1035),
};
wt.Start();
Console.WriteLine("Using Loops:");
Console.WriteLine();
var allPaths = new Search().FindAllPaths(connectedNodes, graph, MAX, Algorithm.Loops);
wt.Stop();
foreach (var path in allPaths)
{
PrintPath(path);
}
Console.WriteLine("Total Seconds: " + wt.Elapsed.TotalSeconds + ", Number of paths: " + allPaths.Count());
Console.WriteLine("***************************************************************************************************");
Console.WriteLine("Using Recursion:");
Console.WriteLine();
wt.Reset();
wt.Start();
allPaths = new Search().FindAllPaths(connectedNodes, graph, MAX, Algorithm.Recursion);
wt.Stop();
foreach (var path in allPaths)
{
PrintPath(path);
}
Console.WriteLine("Total Seconds: " + wt.Elapsed.TotalSeconds + ", Number of paths: " + allPaths.Count());
Console.WriteLine();
}
private IEnumerable<List<int>> FindAllPaths(List<Connection> connectedNodes, Graph graph, int max, Algorithm algorithm)
{
var paths=new Stack<List<int>>();
var blocked=new List<int>();
for (var i = 0; i < connectedNodes.Count; i++)
{
if (!blocked.Contains(connectedNodes[i].FirstNode)) blocked.Add(connectedNodes[i].FirstNode);
if (!blocked.Contains(connectedNodes[i].SecondNode)) blocked.Add(connectedNodes[i].SecondNode);
}
if (algorithm == Algorithm.Recursion)
{
if (FindAllPaths(connectedNodes, 0, max, graph, paths, blocked))
{
Console.WriteLine("BLOCKED");
return new List<List<int>>();
}
}
else if(algorithm==Algorithm.Loops)
{
if (!FindAllPaths2(connectedNodes, 0, max, graph, paths, blocked))
{
Console.WriteLine("BLOCKED");
return new List<List<int>>();
}
}
return paths;
}
private static bool FindAllPaths(List<Connection> connectedNodes,int order,int max, Graph graph, Stack<List<int>> allPaths, List<int> blocked)
{
if (order >= connectedNodes.Count) return false;
var paths = SearchForPaths(graph, connectedNodes[order].FirstNode, connectedNodes[order].SecondNode, max, blocked);
if (paths.Count == 0) return true;
int i;
for (i = 0; i < paths.Count; i++)
{
var path = paths[i];
allPaths.Push(path);
blocked.AddRange(path);
if (!FindAllPaths(connectedNodes, order + 1,max, graph, allPaths, blocked)) break;
allPaths.Pop();
foreach (var j in path)
{
blocked.RemoveAll(num => num==j);
}
paths.RemoveAll(list => IsListsSimilar(list,path));
i--;
}
if (i == paths.Count) return true;
return false;
}
private static bool IsListsSimilar(List<int> L1,List<int> L2)
{
if (L2.Count > L1.Count) return false;
for (int i = 0; i < L2.Count - 1; i++)
{
if (L1[i] != L2[i]) return false;
}
return true;
}
private static List<List<int>> SearchForPaths(Graph graph, int start, int end, int max, List<int> blocked)
{
blocked.Remove(start);
blocked.Remove(end);
var nodePaths = new List<List<int>>();
var visited = new LinkedList<int>();
visited.AddLast(start);
DepthFirstSearch(graph, visited, end, max, blocked, nodePaths);
nodePaths = nodePaths.OrderBy(list => list.Count).ToList();
return nodePaths;
}
private static void DepthFirstSearch(Graph graph, LinkedList<int> visited, int end, int max, List<int> blocked, List<List<int>> paths)
{
var nodes = graph.adjacentNodes(visited.Last.Value);
// examine adjacent nodes
var nodeCount = blocked.Count;
for (int i = 0; i < nodeCount; i++)
{
if (visited.Contains(blocked[i])) return;
}
if (visited.Count > max) return;
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] != end) continue;
visited.AddLast(nodes[i]);
{
paths.Add(new List<int>(visited));
}
visited.RemoveLast();
break;
}
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] == end) continue;
visited.AddLast(nodes[i]);
DepthFirstSearch(graph, visited, end, max, blocked, paths);
visited.RemoveLast();
}
}
private static bool FindAllPaths2(List<Connection> connectedNodes, int order, int max, Graph graph, Stack<List<int>> allPaths, List<int> blocked)
{
if (order >= connectedNodes.Count) return false;
foreach (var path in SearchForPaths2(graph, connectedNodes[order].FirstNode, connectedNodes[order].SecondNode, max, blocked))
{
allPaths.Push(path);
blocked.AddRange(path);
if (!FindAllPaths2(connectedNodes, order + 1, max, graph, allPaths, blocked)) break;
allPaths.Pop();
foreach (var j in path)
{
blocked.RemoveAll(num => num == j);
}
}
return true;
}
private static IEnumerable<List<int>> SearchForPaths2(Graph graph, int start, int end, int max, List<int> blocked)
{
blocked.Remove(start);
blocked.Remove(end);
var visited = new LinkedList<int>();
visited.AddLast(start);
foreach (var VARIABLE in DepthFirstSearch(graph, visited, end, max, blocked))
{
yield return VARIABLE;
}
}
private static IEnumerable<List<int>> DepthFirstSearch(Graph graph, LinkedList<int> visited, int end, int max, List<int> blocked)
{
var nodes = graph.adjacentNodes(visited.Last.Value);
var nodeCount = blocked.Count;
for (int i = 0; i < nodeCount; i++)
{
if (visited.Contains(blocked[i])) yield break;
}
if (visited.Count > max) yield break;
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] != end) continue;
visited.AddLast(nodes[i]);
yield return (new List<int>(visited));
visited.RemoveLast();
break;
}
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] == end) continue;
visited.AddLast(nodes[i]);
foreach (var P in DepthFirstSearch(graph, visited, end, max, blocked))
{
yield return P;
}
visited.RemoveLast();
}
}
private static void PrintPath(List<int> visited)
{
for (int i = 0; i < visited.Count()-1; i++)
{
Console.Write(visited[i]);
Console.Write(" --> ");
}
Console.Write(visited[visited.Count() - 1]);
Console.WriteLine();
Console.WriteLine();
}
}
public class Graph
{
private readonly Dictionary<int, HashSet<int>> map = new Dictionary<int, HashSet<int>>();
public void addEdge(int node1, int node2)
{
HashSet<int> adjacent = null;
map.TryGetValue(node1, out adjacent);
if (adjacent == null)
{
adjacent = new HashSet<int>();
map.Add(node1, adjacent);
}
adjacent.Add(node2);
}
public List<int> adjacentNodes(int last)
{
HashSet<int> adjacent = null;
map.TryGetValue(last, out adjacent);
if (adjacent == null)
{
return new List<int>();
}
return new List<int>(adjacent);
}
}
}
I think the answer lies in how you have numbered the nodes in your grid. For a simple 2-dimensional grid, 4 nodes by 4, you would number them : 00, 01, 02, 03, 10, 11, 12 ... 30, 31, 32, 33. Think of them as composite number strings (not decimal values) acting as dimension-based node addresses.
In a 3-dimensional grid, they would be numbered 000, 001, 002, etc. up to 330, 331, 332, 333.
If you want to find all routes between two points 10 and 22 you can quickly calculate their distance by adding the dimensional differences: 1y is one away from 2y, and x0 is two away from x2. Therefore the node distance is 3, you will need to travel over 3 edges (connecting 4 nodes in total) to reach the destination.
The solution space (the only nodes that could ever be involved in a solution route) can be enumerated by creating a set of embedded FOR/NEXT loops, one for each dimension. In this case, the start and end values of 10 and 22 would produce: 10, 11, 12, 20, 21 and 22.
Now comes the clever bit. You can precompute (prepare) a table of 'forwarding' connections between the nodes in your array. Node 10 connects to 20 and 11 (both 1 dimensional difference away). From that you can generate a sequence of valid pathways from 10 to 22 by adding one to a dimension difference in which ever direction you plan to move (in a 2-D array you only get to choose one of two ways. In 3-D you get three choices).
Each answer should be the shortest possible distance. The computation time for this approach should be milliseconds. On a steam powered ZX81!

Categories

Resources