Permutation of a list of strings algorithm - c#

I need help understanding how to write a permutation algorithm. (if this is even permutation, they have to be in order and use the same values).
List<string> str = new List<string>{"a", "b", "c", "d"};
How can I get a list of each permutation available in this list? For eg.
a, b, c, d
ab, c, d
ab, cd
abc, d
abcd
a, bc, d
a, bcd
a, b, cd
For some reason I cant find a pattern to start with. I'd also like to be able to disregard permutation when a joined string has a count of like X characters. So if X was 4, in that list, number 5 wouldn't exist and there would be 7 permutations.
private List<string> permute(List<string> values, int maxPermutation)
{
//alittle help on starting it would be great :)
}
I looked and read this, but he does not keep the order.

This is rather straightforward: you have three spots where you could either put a comma or to put nothing. There are eight combinations corresponding to 2^3 binary numbers.
For each number from 0 to 7, inclusive, produce a binary representation. Put a comma in each position where binary representation has 1; do not put comma where there's zero.
for (int m = 0 ; m != 8 ; m++) {
string s = "a";
if ((m & 1) != 0) s += ",";
s += "b";
if ((m & 2) != 0) s += ",";
s += "c";
if ((m & 4) != 0) s += ",";
s += "d";
Console.WriteLine(s);
}

You could take a recursive approach: Take the first letter, build all possible combinations starting with the second one (this is the recursion...) and prepend the first letter to each of them. Then take the first two letters together, recursively build all combinations starting with the third one. And so on ...
As for you additional requirement: If you want to exclude all "combinations" containing a string with X letters, just skip this number when constructing the first string.

The Binary approach above is correct and this is actually a partitioning problem (but not "The Partitioning Problem") and not a permutation problem.
http://en.wikipedia.org/wiki/Partition_of_a_set
Watch out because of the number of partitions grows faster than exponentially (e^e^n) so it will be really slow for large strings.

Try the following code. I haven't tested it, but I think it's what you are looking for.
List<string> str = new List<string>{ "a", "h", "q", "z", "b", "d" };
List<List<string>> combinations = combine(str.OrderBy(s=>s).ToList());
List<List<string>> combine(List<string> items)
{
List<List<string>> all = new List<List<string>>();
// For each index item in the items array
for(int i = 0; i < items.Length; i++)
{
// Create a new list of string
List<string> newEntry = new List<string>();
// Take first i items
newEntry.AddRange(items.Take(i));
// Concatenate the remaining items
newEntry.Add(String.concat(items.Skip(i)));
// Add these items to the main list
all.Add(newEntry);
// If this is not the last string in the list
if(i + 1 < items.Length)
{
// Process sub-strings
all.AddRange(combine(items.Skip(i + 1).ToList()));
}
}
return all;
}
If you need to generate combinations (or permutations or variations), then Combinatorics is a fantastic library.

Related

Comparing two lists of Strings and counting the matches, possible performance problem

I want to count the amount of matches when comparing a List of Strings A with another List of Strings B. A contains elements from a Set Z and B is a subset of Z. A can contain duplicates but B cannot. I want duplicates to be counted individually so 2x match with the same element from B should yield 2 counts.
List A's strings contain a prefix which i decided to cut out but i could also leave the original string elements unmodified
Example:
List<string> A = {"a","b","c","a"}
List<string> B = {"a", "c"}
matches would be 3 (two times matched with a and once matched with c)
I have a solution that should work and in very rare cases it does work but my suspicion is that due to time constraints during execution it fails 90% of the time.
var _A = A.Select(str => str.ToLower()).ToList(); //B can be modified for this step to be not necessary but increases the length of each string element
_A = _A.Select(str => str.Replace(" ", "")).ToList(); //B can be modified for this step to be not necessary but increases the length of each string element
_A = _A.Select(x => x.Substring("drops".Length)).ToList(); //B can be modified for this step to be not necessary but increases the length of each string element
sum = _A.Where(x => B.Any(y => y.Equals(x))).Count();
This is O(A*B) if im not mistaken.
Is there anything more i can do to reduce the time complexity ?
You use an HashSet<string>. It is O(1) both in Add() and Contains().
var a = new[] { "a", "b", "c", "a" };
var b = new[] { "a", "c" };
var hs = new HashSet<string>(b);
var cnt = a.Count(x => hs.Contains(x));
This has a complexity of O(b+a), O(b) for the Add(), O(A) for the Contains().

Loop Count String (ex A to ABC) C# [duplicate]

This question already has answers here:
Iterating through the Alphabet - C# a-caz
(10 answers)
Closed 6 years ago.
I am not sure how to search for this, or I would. What I need to do is count up with letters rather than numbers. the input will only contain letters and numbers, no spaces, or dashes.
For example, if the user enters "A" for start and "ABC" for end it would output, A, B, C,...AA, AB, AC,...ABC.
I can do it by breaking everything down to an array, increase, the last index, until "Z", then, increase the index, check if it is equals end, then loop again.When "Z" is hit and it has a number (treated as a string) start to loop through "0 - 9".
It just seems there would be an easier way, than what I am thinking. I seen one solution in Java that I could convert, but not fully understanding how it works SO Post it is using MOD and does not really compare values. This is just a small project for a computer lab, to generate NetBIOS names, for another program to use. All the names are sequential.
Thanks,
Dave
Dim array1 As String() = {"a", "b", "c"}
Dim array2 As String() = {"a", "b", "c"}
Dim result = array1.SelectMany(Function(f) array2, Function(f, a) New With {Key .first = f, Key .second = a})
Dim s As String = String.Empty
For i As Integer = 0 To result.Count - 1
s += result(i).first + result(i).second + " "
Next
MessageBox.Show(s)
output:
aa
ab
ac
ba
bb
bc
ca
cb
cc
I think this may be close to what you are after. Similar to a cross-join in SQL. This works in VB.Net but you can run a code converter
EDIT: (Ran through code converter (vb to c#), untested)
string[] array1 = {
"a",
"b",
"c"
};
string[] array2 = {
"a",
"b",
"c"
};
dynamic result = array1.SelectMany(f => array2, (f, a) => new {
first = f,
second = a
});
string s = string.Empty;
for (int i = 0; i <= result.Count - 1; i++) {
s += result(i).first + result(i).second + " ";
}
MessageBox.Show(s);
//=======================================================
//Service provided by Telerik (www.telerik.com)
//Conversion powered by NRefactory.
//Twitter: #telerik
//Facebook: facebook.com/telerik
//=======================================================

I want to make a new array from existing one

My problem today is about creating an array from an existing one.
My "parent" array contains elements with two characters.
My new array's elements should contain 20 elements from the "parent" array.
Example:
string[] parentArray = {aa, bb, cc, df, ds, aa, zz, xx, cc, ww, fg, qq, ww, ee,
key: (0) (1) (2) (3) (4) (6) (7) (8) (9) (10)........ rr, dd, ss, qq, dd, ss, sa, wq, ee, rr}
string[] childArray = {aabbccdfdsaazzxxccwwfgqqwweerrddssqqddss,.....}
(1)
With some of the extension functions for enumerables you can go a long way here.
int cursor = 0;
List<string> result = new List<string>();
while (cursor < parentArray.Length)
{
result.Add(String.Join("", parentArray.Skip(cursor).Take(20)));
cursor += 20;
}
string[] childArray = result.ToArray();
This function walks over your array, fetches 20 elements (or less in case there aren't 20 elements left) and merges them into a string and add that string to a list. I made use of the String.Join method to concat the string. That works nicely here.
The Skip function and the Take function are extension functions for IEnumerable and do just what they say.
EDIT: I did assume that your source array is longer and may contain multiple blocks of 20 elements that need to be moved to the childArray
EDIT2: In case you have a load of values in your parentArray you may want to go a different way, to get some more performance out of it. In that case I suggest using the StringBuilder.
var builder = new Text.StringBuilder();
List<string> result = new List<string>();
for (int cursor = 0; cursor < parentArray.Length; cursor++)
{
if (builder.Length > 0 && (cursor % 20) == 0)
{
result.Add(builder.ToString());
builder.Length = 0;
}
builder.Append(parentArray[cursor]);
}
/* At this point you can choose to add the remaining elements to the list or not. */
if (builder.Length > 0)
{
result.Add(builder.ToString());
}
string[] childArray = result.ToArray();
Sounds as if a simple LINQ-statement will do what you need:
var myArr = parent.Take(20).ToArray();
This will select the 20 first elements of your parent-array.
EDIT: To do this with all of your elements within parent loop its entries:
List<string> result= new List<string>();
while(parent.Any()) {
result.Add(String.Join("", parent.Take(20).ToArray());
parent = parent.Skip(20).ToArray();
}
Finally convert your list back to an array using result.ToArray.
You can make a for loop on the parent array and add the element inside the array to a string like the following
String str="";
for (int i=0;i<count(parent);i++){
str+=parent[i].tostring();
}
Then make a new string array and at the first index put the str variable...
Hope this help you if this what u r asking for.

String Array Searching

I had an interview for a Jr. developer position a few days ago, and they asked:
"If you had an array of letters "a" and "b" how would you write a method to count how many instances of those letters are in the array?"
I said that you would have a for loop with an if else statement that would increment 1 of 2 counter variables. After that, though, they asked how I would solve that same problem, if the array could contain any letter of the alphabet. I said that I would go about it the same way, with a long IF statement, or a switch statement. In hindsight, that doesn't seem so efficient; is there an easier way to go about doing this?
You could declare the array of size 256 (number of possible character codes) zero it and simply increase the one which corresponds to a char code you read.
For example if you are reading the 'a' the corresponding code is ASCII 97 so you increase the array[97] you can optimize the amount of memory decreasing the code by 97 (if you know the input is going to be characters only) you also need to be aware what to do with capital characters ( are you conciser them as different or not) also in this case you need to take care to decrease the character by 65.
So at the end code would look like this:
int counts[122 - 97] = {0}; // codes of a - z
char a = get_next_char();
if ( is_capital(a)){
counts[a - 65]++;
}
else
{
counts[a - 97] ++;
}
this code assumes the 'A' = 'a'
if its not the case you need to have different translation in the if's but you can probably figure out the idea now. This saves a lot of comparing as opposed to your approach.
Depending on whether the objective is CPU efficiency, memory efficiency, or developer efficiency, you could just do:
foreach(var grp in theString.GroupBy(c => c)) {
Console.WriteLine("{0}: {1}", grp.Key, grp.Count());
}
Not awesome efficiency, but fine for virtually on non-pathological scenarios. In real scenarios, due to unicode, I'd probably use a dictionary as a counter - unicode is to big to pre-allocate an array.
Dictionary<char, int> counts = new Dictionary<char, int>();
foreach(char c in theString) {
int count;
if(!counts.TryGetValue(c, out count)) count = 0;
counts[c] = count + 1;
}
foreach(var pair in counts) {
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
You can create Dictionary<string, int>, then iterate through array, check if element exist as key in dictionary and increment value.
Dictionary<string, int> counter = new Dictionary<string, int>();
foreach(var item in items)
{
if(counter.ContainsKey(item))
{
counter[item] = counter[item] + 1;
}
}
Here is wonderful example given, it may resolve your query.
http://www.dotnetperls.com/array-find
string[] array1 = { "cat", "dog", "carrot", "bird" };</br>
//
// Find first element starting with substring.
//
string value1 = Array.Find(array1,
element => element.StartsWith("car", StringComparison.Ordinal));</br>
//
// Find first element of three characters length.
//
string value2 = Array.Find(array1,
element => element.Length == 3);
//
// Find all elements not greater than four letters long.
//
string[] array2 = Array.FindAll(array1,
element => element.Length <= 4);
Console.WriteLine(value1);
Console.WriteLine(value2);
Console.WriteLine(string.Join(",", array2));

Get all possible word combinations

I have a list of n words (let's say 26). Now I want to get a list of all possible combinations, but with a maximum of k words per row (let's say 5)
So when my word list is: aaa, bbb, ..., zzz
I want to get:
aaa
bbb
...
aaabbb
aaaccc
...
aaabbbcccdddeeefff
aaabbbcccdddeeeggg
...
I want to make it variable, so that it will work with any n or k value.
There should be no word be twice and every combinations needs to be taken (even if there are very much).
How could I achieve that?
EDIT:
Thank you for your answers. It is not an assignment. Is is just that I forgot the combinations of my password and I want to be sure that I have all combinations tested. Although I have not 26 password parts, but this made it easier to explain what I want.
If there are other people with the same problem, this link could be helpfull:
Generate word combination array in c#
i wrote simple a function to do this
private string allState(int index,string[] inStr)
{
string a = inStr[index].ToString();
int l = index+1;
int k = l;
var result = string.Empty;
var t = inStr.Length;
int i = index;
while (i < t)
{
string s = a;
for (int j = l; j < k; j++)
{
s += inStr[j].ToString();
}
result += s+",";
k++;
i++;
}
index++;
if(index<inStr.Length)
result += allState(index, inStr);
return result.TrimEnd(new char[] { ',' });
}
allState(0, new string[] { "a", "b", "c"})
You could take a look at this
However, if you need to get large numbers of combinations (in the tens of millions) you should use lazy evaluation for the generation of the combinations.

Categories