Implementing method in a functional style - c#

I have the following method:
private List<string> CreateSegments(string virtualPath)
{
List<string> segments = new List<string>();
int i = virtualPath.IndexOf('/', 1);
while (i >= 0 && i < virtualPath.Length)
{
var segment = virtualPath.Substring(0, i);
if (!string.IsNullOrWhiteSpace(segment))
{
segments.Add(segment);
segments.Add(VirtualPathUtility.Combine(segment, "default"));
}
i = virtualPath.IndexOf('/', i + 1);
}
segments.Add(virtualPath);
segments.Add(VirtualPathUtility.Combine(virtualPath, "default"));
return segments;
}
Basically, it creates path segments which I will use to check if a file exists in any of those segments. Like this:
string[] extensions = GetRegisteredExtensions();
HttpServerUtilityBase server = HttpContext.Current.Server;
List<string> segments = CreateSegments(virtualPath);
// check if a file exists with any of the registered extensions
var match = extensions.SelectMany(x => segments.Select(s => string.Format("{0}.{1}", s, x)))
.FirstOrDefault(p => System.IO.File.Exists(server.MapPath(p)));
All the above code looks like it could use some clean up and optimization, but I'm looking for a way to use LINQ if possible to generate the segments.
Something like: var segments = virtualPath.Split('/').SelectMany(...) and get a result similar to the following:
/path
/path/default
/path/to
/path/to/default
/path/to/file
/path/to/file/default
Where virtualPath would contain the value "/path/to/file"
EDIT: Changed string.Format("{0}/{1}", ...) to VirtualPathUtility.Combine(..., ...)
Any ideas?

One way would be to incrementally select the path segments, then "join" it with an empty string and "/default" to get the two variations:
string path = #"/path/to/file";
string temp = "";
var query = path.Split('/')
.Where(s => !string.IsNullOrEmpty(s))
.Select((p) => {temp += ("/" + p); return temp;} )
.SelectMany(s => new[]{"","/default"}.Select (d => s + d) );

If you first define an extension method like this:
public static IEnumerable<int> SplitIndexes(this string subject, char search)
{
for(var i = 1; i < subject.Length; i++)
{
if(subject[i] == search)
{
yield return i;
}
}
yield return subject.Length;
}
Then you could do this:
var endings = new string[] { string.Empty, "/default" };
var virtualPath = "/path/to/file";
var results =
from i in virtualPath.SplitIndexes('/')
from e in endings
select virtualPath.Substring(0, i) + e;
Or if you prefer query syntax:
var endings = new string[] { string.Empty, "/default" };
var virtualPath = "/path/to/file";
var results = virtualPath.SplitIndexes('/')
.SelectMany(i => endings.Select(e => virtualPath.Substring(0, i) + e));
The result will be:
/path
/path/default
/path/to
/path/to/default
/path/to/file
/path/to/file/default
As others have suggested, you can this in a more platform independent way by using Path.Combine, like this:
var endings = new string[] { string.Empty, "default" }; // Note: no / before default
var results =
from i in virtualPath.SplitIndexes(Path.DirectorySeparatorChar)
from e in endings
select Path.Combine(virtualPath.Substring(0, i), e);

This might do the trick. It is not the most succinct code but it seems very readable to me. It uses string concatenation because for short strings, like paths or URLs, it is faster than any of the alternatives.
Edit: fixed and tested.
var query = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries)
.Aggregate(new List<string>(), (memo, segment) => {
memo.Add(memo.DefaultIfEmpty("").Last() + "/" + segment);
return memo;
}).Aggregate(new List<string>(), (memo, p) => {
memo.Add(p);
memo.Add(p + "/default");
return memo;
});

The higher-order function you're looking for is called scan. There is no such function in normal LINQ, but you can find it in MoreLinq. Using that, your code could look like this:
private List<string> CreateSegments(string virtualPath)
{
return virtualPath.Split('/')
.Scan((s1, s2) => s1 + '/' + s2)
.Skip(1)
.SelectMany(p => new[] { p, p + "/default" })
.ToList();
}
This assumes your path will be always an absolute path starting with a /. For relative paths, you will need to remove the .Skip(1) part.
If you don't want to get MoreLinq just for this one method, you can just copy its source into your project.

The provided answers so far are more succinct, but this is what I came up with:
public static IEnumerable<string> PossiblePaths(string basePath)
{
return PossiblePaths(basePath.Split(new[] { "/" },
StringSplitOptions.RemoveEmptyEntries));
}
private static IEnumerable<string> PossiblePaths(IEnumerable<string> segments,
string current = "/")
{
if (segments.Count() == 0)
{
return new string[0];
}
else
{
string next = current + segments.First();
return new[] { next, next + "/default" }
.Concat(PossiblePaths(segments.Skip(1), next + "/"));
}
}

Something like this:
public static IEnumerable<string> EnumerateSegments( this IEnumerable<string> segments )
{
StringBuilder sb = new StringBuilder() ;
foreach ( string segment in segements )
{
sb.Append( Path.DirectorySeparatorChar ).Append( segment ) ;
yield return sb.ToString() ;
int n = sb.Length ;
sb.Append( Path.DirectorySeparatorChar ).Append("default") ;
yield return sb.ToString() ;
sb.Length = n ;
}
}
ought to do you.

Related

Finding filenames containing version numbers in C#

I have file names with version numbers embedded, similar to NuGet's naming scheme. Examples:
A.B.C.1.2.3.4.zip
A.B.C.1.2.3.5.zip
A.B.C.3.4.5.dll
A.B.C.1.2.3.6.zip
A.B.C.1.2.3.dll
X.Y.Z.7.8.9.0.zip
X.Y.Z.7.8.9.1.zip
Given a pattern "A.B.C.1.2.3", how do I find all those files and directories that match, regardless of version number? I support both major.minor.build.revision and major.minor.build schemes.
That is, given "A.B.C.1.2.3", return the following list:
A.B.C.1.2.3.4.zip
A.B.C.1.2.3.5.zip
A.B.C.1.2.3.6.zip
A.B.C.1.2.3.dll
A.B.C.3.4.5.dll
Bonus points for determining which file name has the highest version.
If you know the filenames end with the version, you could Split the filename string on .. Then iterate backwards from the end (skipping the extension) and stop on the first non-numeric string. (TryParse is probably good for this.) Then you can string.Join the remaining parts and you have the package name.
Do this for the search term to find the package name, then each file in the directory, and you can compare just the package names.
Credits to jdwweng for his answer as well as 31eee384 for his thoughts. This answer basically combines both ideas.
First, you can create a custom class like so:
class CustomFile
{
public string FileName { get; private set; }
public Version FileVersion { get; private set; }
public CustomFile(string file)
{
var split = file.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
int versionIndex;
int temp;
for (int i = split.Length - 2; i >= 0; i--)
{
if (!Int32.TryParse(split[i], out temp))
{
versionIndex = i+1;
break;
}
}
FileName = string.Join(".", split, 0, versionIndex);
FileVersion = Version.Parse(string.Join(".", split, versionIndex, split.Length - versionIndex - 1));
}
}
Using it to parse the filename, you can then filter based on it.
string[] input = new string[] {
"A.B.C.D.1.2.3.4.zip",
"A.B.C.1.2.3.5.zip",
"A.B.C.3.4.5.dll",
"A.B.C.1.2.3.6.zip",
"A.B.C.1.2.3.dll",
"X.Y.Z.7.8.9.0.zip",
"X.Y.Z.7.8.9.1.zip"
};
var parsed = input.Select(x => new CustomFile(x));
var results = parsed
.Where(cf => cf.FileName == "A.B.C")
.OrderByDescending(cf=>cf.FileVersion)
.ToList();
In this example, the first element would have the highest version.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] input = new string[] {
"A.B.C.1.2.3.4.zip",
"A.B.C.1.2.3.5.zip",
"A.B.C.3.4.5.dll",
"A.B.C.1.2.3.6.zip",
"A.B.C.1.2.3.dll",
"X.Y.Z.7.8.9.0.zip",
"X.Y.Z.7.8.9.1.zip"
};
var parsed = input.Select(x => x.Split(new char[] { '.' }))
.Select(y => new
{
name = string.Join(".", new string[] { y[0], y[1], y[2] }),
ext = y[y.Count() - 1],
major = int.Parse(y[3]),
minor = int.Parse(y[4]),
build = int.Parse(y[5]),
revision = y.Count() == 7 ? (int?)null : int.Parse(y[6])
}).ToList();
var results = parsed.Where(x => (x.major >= 1) && (x.major <= 3)).ToList();
var dict = parsed.GroupBy(x => x.name, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
var abc = dict["A.B.C"];
}
}
}
​
​
you can use new Version() to compare versions like this:
List<string> fileNames = new List<string>();
fileNnames.AddRange(new[] {
"A.B.C.1.2.3.4.zip",
"A.B.C.1.2.3.5.zip",
"A.B.C.3.4.5.dll",
"A.B.C.1.2.3.6.zip",
"A.B.C.1.2.3.dll",
"X.Y.Z.7.8.9.0.zip",
"X.Y.Z.7.8.9.1.zip" });
string filter = "a.b.c";
var files = fileNames
//Filter the filenames that start with your filter
.Where(f => f
.StartsWith(filter, StringComparison.InvariantCultureIgnoreCase)
)
//retrieve the version number and create a new version element to order by
.OrderBy(f =>
new Version(
f.Substring(filter.Length + 1, f.Length - filter.Length - 5)
)
);
Try to use regular expression like in example below
var firstPart = Console.ReadLine();
var names = new List<string>
{
"A.B.C.1.2.3.4.zip",
"A.B.C.1.2.3.5.zip",
"A.B.C.1.2.3.6.zip",
"A.B.C.1.2.3.dll",
"X.Y.Z.7.8.9.0.zip",
"X.Y.Z.7.8.9.1.zip"
};
var versionRegexp = new Regex("^" + firstPart + "\\.([\\d]+\\.){1}([\\d]+\\.){1}([\\d]+\\.){1}([\\d]+\\.)?[\\w\\d]+$");
foreach (var name in names)
{
if (versionRegexp.IsMatch(name))
{
Console.WriteLine(name);
foreach (Group group in versionRegexp.Match(name).Groups)
{
Console.WriteLine("Index {0}: {1}", group.Index, group.Value);
}
}
}
Console.ReadKey();
This works using only LINQ, assuming the file name itself doesn't end with a digit:
List<string> names = new List<string> { "A.B.C.1.2.3.4.zip",
"A.B.C.1.2.3.5.zip",
"A.B.C.3.4.5.dll",
"A.B.C.1.2.3.6.zip" ,
"A.B.C.1.2.3.dll",
"X.Y.Z.7.8.9.0.zip",
"X.Y.Z.7.8.9.1.zip" };
var groupedFileNames = names.GroupBy(file => new string(Path.GetFileNameWithoutExtension(file)
.Reverse()
.SkipWhile(c => Char.IsDigit(c) || c == '.')
.Reverse().ToArray()));
foreach (var g in groupedFileNames)
{
Console.WriteLine(g.Key);
foreach (var file in g)
Console.WriteLine(" " + file);
}
First of all I think you can use Version class for comparison.
I believe function below can get you versions starting with certain name.
It matches the starting name then performs a non greedy search until a dot and digit followed by 2 or 3 dot digit pair and any character after.
public static List<Version> GetLibraryVersions(List<string> files, string Name)
{
string regexPattern = String.Format(#"\A{0}(?:.*?)(?:\.)(\d+(?:\.\d+){{2,3}})(?:\.)(?:.*)\Z", Regex.Escape(Name));
Regex regex = new Regex(regexPattern);
return files.Where(f => regex.Match(f).Success).
Select(f => new Version(regex.Match(f).Groups[1].Value)).ToList();
}

Linq to get distinct subdirectories from list of paths

I am trying to make a File Directory browser in C# for a project.
I start with the current path (for this example it will be '/').
From the list of paths that I have
Example: /a/b, /a/bb, /a/bbb, /b/a, /b/aa, /b/aaa, /c/d, /d/e
I would like to return a list of distinct subdirectories
Expected return: /a/, /b/, /c/, /d/
How would one go about using LINQ to accomplish this?
I think this just about covers it. Sample console app:
public static void Main()
{
string[] paths = new[] { "/a/b", "/a/bb", "/a/bbb", "/b/a", "/b/aa", "/b/aaa", "/c/d", "/d/e" };
string root = "/";
Console.WriteLine(string.Join(", ", paths.Select(s => GetSubdirectory(root, s)).Where(s => s != null).Distinct()));
}
static string GetSubdirectory(string root, string path)
{
string subDirectory = null;
int index = path.IndexOf(root);
Console.WriteLine(index);
if (root != path && index == 0)
{
subDirectory = path.Substring(root.Length, path.Length - root.Length).Trim('/').Split('/')[0];
}
return subDirectory;
}
See fiddle: http://dotnetfiddle.net/SXAqxY
Sample input: "/"
Sample output: a, b, c, d
Sample input: "/a"
Sample output: b, bb, bbb
I may missing the point, but wouldn't something like this be what you are looking for?
var startingPath = #"c:\";
var directoryInfo = new DirectoryInfo(startingPath);
var result = directoryInfo.GetDirectories().Select(x => x.FullName).ToArray();
The result would be an array of paths to the various immediate sub directories (example):
"c:\Boot"
"c:\Temp"
etc.
void Main()
{
string [] paths = { #"/a/b", #"/a/bb", #"/a/bbb", #"/b/a", #"/b/aa", #"/b/aaa", #"/c/d", #"/d/e" };
var result = paths.Select(x => x.Split('/')[1]).Distinct();
result.Dump();
}
If you don't know if you have a leading / then use this:
var result = paths.Select(x =>x.Split(new string [] {"/"},
StringSplitOptions.RemoveEmptyEntries)[0])
.Distinct();
You can use Path.GetPathRoot
var rootList = new List <string>();
foreach (var fullPath in myPaths)
{
rootList.Add(Path.GetPathRoot(fullPath))
}
return rootList.Distinct();
Or:
myPaths.Select(x => Path.GetPathRoot(x)).Distinct();
Or use Directory.GetDirectoryRoot:
myPaths.Select(x => Directory.GetDirectoryRoot(x)).Distinct();
Edit
If you want the N+1 path you could do:
string dir = #"C:\Level1\Level2;
string root = Path.GetPathRoot(dir);
string pathWithoutRoot = dir.Substring(root.Length);
string firstDir = pathWithoutRoot.Split(Path.DirectorySeparatorChar).First();
Assuming you have a list of paths named paths, you can do something like this:
string currentDirectory = "/";
var distinctDirectories = paths.Where(p => p.StartsWith(currentDirectory)
.Select(p => GetFirstSubDir(p, currentDirectory)).Distinct();
...
string GetFirstSubDir(string path, string currentDirectory)
{
int index = path.IndexOf('/', currentDirectory.Length);
if (index >= 0)
return path.SubString(currentDirectory.Length - 1, index + 1 - currentDirectory.Length);
return path.SubString(currentDirectory.Length - 1);
}

Comparing strings with hyphen

I have some strings in a list
List<string> list = new List<string>{ "100-1", "100-11", "100-3", "100-20" }
I used following code to sort which is picked from this location
void Main()
{
string[] things= new string[] { "100-1", "100-11", "100-3", "100-20" };
foreach (var thing in things.OrderBy(x => x, new SemiNumericComparer()))
{
Console.WriteLine(thing);
}
}
public class SemiNumericComparer: IComparer<string>
{
public int Compare(string s1, string s2)
{
if (IsNumeric(s1) && IsNumeric(s2))
{
if (Convert.ToInt32(s1) > Convert.ToInt32(s2)) return 1;
if (Convert.ToInt32(s1) < Convert.ToInt32(s2)) return -1;
if (Convert.ToInt32(s1) == Convert.ToInt32(s2)) return 0;
}
if (IsNumeric(s1) && !IsNumeric(s2))
return -1;
if (!IsNumeric(s1) && IsNumeric(s2))
return 1;
return string.Compare(s1, s2, true);
}
public static bool IsNumeric(object value)
{
try {
int i = Convert.ToInt32(value.ToString());
return true;
}
catch (FormatException) {
return false;
}
}
}
My output is 100-1, 100-11, 100-20, 100-3
I believe it is taking - as decimal and comparing the values. Actually I was expecting the result to be
100-1, 100-3, 100-11, 100-20.
I just wanted to know on what basis it is actually performing sort. Any help is appreciated. Even I expect it to treat 100-2 and 100-20 differently.
Just on the fly, I have seen in Infragistic control grid that sorting in it produces the same result as I was expecting here to be.
I have many other string values in the list, some are integers, doubles and so on. Hyphen is just a case mentioned here.
var sorted = things.Select(s => s.Split('-'))
.OrderBy(x => double.Parse(x[0]))
.ThenBy(x => double.Parse(x[1]))
.Select(x=>String.Join("-",x))
.ToList();
This should work as expected:
string[] things= new string[] { "100-1", "100-11", "100-3", "100-20" };
IEnumerable<string> ordered = things
.Select(s => new
{
str = s,
firstPart = s.Split('-').ElementAtOrDefault(0),
secondPart = s.Split('-').ElementAtOrDefault(1)
})
.OrderBy(x => int.Parse(x.firstPart))
.ThenBy(x => int.Parse(x.firstPart))
.Select(x => x.str);
foreach (string s in ordered)
Console.WriteLine(s);
Although it assumes that your data is strict, otherwise you're open for exceptions, f.e at int.Parse(x.firstPart).
Demo: http://ideone.com/UJ5Yt4
If you want to sort the items by the 2nd number (after hyphen), You need to parse the string to a number then order by using it. you can try:
string[] things = new string[] { "100-1", "100-11", "100-3", "100-20" };
var test = things.OrderBy(r => int.Parse(r.Split('-')[1])).ToArray();
The reason your current code is not working is probably due to the fact that it can't parse the string 100- to an integer value and your function IsNumeric is returning false.

How Sort A List With C# For A Specific Part Of Every Item In List

please see the list below :
string[] Separator = new string[] { "__" };
string[] lines_acc = File.ReadAllLines(accfilePath);
List<string> list_lines_acc = new List<string>(lines_acc);
List<string> list_lines_silver_count = new List<string>();
FileStream fs_ = null;
if (!File.Exists(silver_countfilePath))
{
using (fs_ = File.Create(silver_countfilePath))
{
foreach (string line_acc in list_lines_acc)
{
string[] line_acc_ar = line_acc.Split(Separator, StringSplitOptions.None);
string line_acc_new = line_acc_ar[0] + "__" + line_acc_ar[1] + "__" + line_acc_ar[3] + "__" + line_acc_ar[4] + "__" + "0";
list_lines_silver_count.Add(line_acc_new);
}
File.WriteAllLines(silver_countfilePath, list_lines_silver_count);
}
}
else
{
string[] lines_silver_count = File.ReadAllLines(silver_countfilePath);
list_lines_silver_count = new List<string>(lines_silver_count);
}
i want to sort list_lines_silver_count by line_acc_ar[4] part!
that part is a string like -> 325423 -> mean i can convert it to an integer.
how can i do that job?
One way is to implement the comparer and provide it as an argument to the Sort function:
public class SilverCountLineComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string xPart = x.Split(new char[] {'_'}, StringSplitOptions.RemoveEmptyEntries)[3];
string yPart = y.Split(new char[] {'_'}, StringSplitOptions.RemoveEmptyEntries)[3];
int xNum = Int32.Parse(xPart);
int yNum = Int32.Parse(yPart);
return xNum.CompareTo(yNum);
}
}
And to sort call it like this:
list_lines_silver_count.Sort(new SilverCountLineComparer());
Change the foreach:
foreach (var line_acc_ar in list_lines_acc
.Select(s => s.Split(Separator, StringSplitOptions.None)
.OrderBy(a => a[4])) {
}
Further refactorings could make the code more elegant, but I think this piece of LINQ should do the job.
You can try this
sorted using a Comparison generic delegate representing the CompareStringByInteger method
public static int CompareStringByInteger(string x, string y)
{
if (x == null)
{
if (y == null)
return 0;
else
return -1;
}
else
{
try{
return Convert.ToInt32(x).CompareTo(Convert.ToInt32(y));
}catch{
return x.CompareTo(y);
}
}
}
and apply it in sort method.
list_lines_silver_count.Sort(CompareStringByInteger);
You can use Linq:
int number = 0;
string[] lines_silver_count = File
.ReadLines(silver_countfilePath)
.Select(l => new {
Line = l,
Parts = l.Split(Separator, StringSplitOptions.None)
})
.Where(x => x.Parts.Length > 4
&& int.TryParse(x.Parts[4], out number))
.OrderBy(x => number)
.Select(x => x.Line)
.ToArray();
public class MyCompare : IComparer<string>
{
public int Compare(string x, string y)
{
//get line_acc_ar[4] part from strings x and y
string[] Separator = new string[] { "__" };
string partX = x.Split(Separator, StringSplitOptions.None)[3];
string partY = y.Split(Separator, StringSplitOptions.None)[3];
int intPartX = int.Parse(partX );
int inrPartY = int.Parse(partY );
return intPartX.CompareTo(inrPartY)
}
}
list_lines_silver_count.OrderBy(a => a, new MyCompare());

Combining arrays of strings together

I'm looking to combine the contents of two string arrays, into a new list that has the contents of both joined together.
string[] days = { "Mon", "Tue", "Wed" };
string[] months = { "Jan", "Feb", "Mar" };
// I want the output to be a list with the contents
// "Mon Jan", "Mon Feb", "Mon Mar", "Tue Jan", "Tue Feb" etc...
How can I do it ? For when it's only two arrays, the following works and is easy enough:
List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
foreach (var wordOne in wordsOne)
{
foreach (string wordTwo in wordsTwo)
{
combinedWords.Add(wordOne + " " + wordTwo);
}
}
return combinedWords;
}
But I'd like to be able to pass varying numbers of arrays in (i.e. to have a method with the signature below) and have it still work.
List<string> CombineWords(params string[][] arraysOfWords)
{
// what needs to go here ?
}
Or some other solution would be great. If it's possible to do this simply with Linq, even better!
What you want to do is actually a cartesian product of all the arrays of words, then join the words with spaces. Eric Lippert has a simple implementation of a Linq cartesian product here. You can use it to implement CombineWords:
List<string> CombineWords(params string[][] arraysOfWords)
{
return CartesianProduct(arraysOfWords)
.Select(x => string.Join(" ", x))
.ToList();
}
To cross join on any amount of arrays of strings:
// Define other methods and classes here
List<string> CombineWords(params string[][] arraysOfWords)
{
if (arraysOfWords.Length == 0)
return new List<string>();
IEnumerable<string> result = arraysOfWords[0];
foreach( string[] words in arraysOfWords.Skip(1) )
{
var tempWords = words;
result = from r in result
from w in tempWords
select string.Concat(r, " ", w);
}
return result.ToList();
}
Code below works for any number of arrays (and uses linq to some degree):
List<string> CombineWords(params string[][] wordsToCombine)
{
if (wordsToCombine.Length == 0)
return new List<string>();
IEnumerable<string> combinedWords = wordsToCombine[0].ToList();
for (int i = 1; i < wordsToCombine.Length; ++i)
{
var temp = i;
combinedWords = (from x in combinedWords from y in wordsToCombine[temp]
select x + " " + y);
}
return combinedWords.ToList();
}
public static List<string> CombineWords(params string[][] arraysOfWords)
{
var strings = new List<string>();
if (arraysOfWords.Length == 0)
{
return strings;
}
Action<string, int> combineWordsInternal = null;
combineWordsInternal = (baseString, index) =>
{
foreach (var str in arraysOfWords[index])
{
string str2 = baseString + " " + str;
if (index + 1 < arraysOfWords.Length)
{
combineWordsInternal(str2, index + 1);
}
else
{
strings.Add(str2);
}
}
};
combineWordsInternal(string.Empty, 0);
return strings;
}
Second try... I'm not able to do it in LINQ... A little too much complex to linquize correctly :-)
I'm using a local anonymous function (and showing that it's quite complex to recurse on anonymous functions, because you have to declare them separately)
This is a non-recursive solution which buffers strings as it progresses, to reduce the number of concatenations. Therefore it should also be usable for more arrays.
It also preserves your desired order - the items in the first array will always be at the beginning of the resulting string.
var s1 = new string[] { "A", "B", "C" };
var s2 = new string[] { "1", "2", "3", "4" };
var s3 = new string[] { "-", "!", "?" };
var res = Combine(s1, s2, s3);
And the function in question:
private List<string> Combine(params string[][] arrays)
{
if (arrays.Length == 1)
{
// The trivial case - exit.
return new List<string>(arrays[0]);
}
IEnumerable<string> last = arrays[arrays.Length - 1];
// Build from the last array, progress forward
for (int i = arrays.Length - 2; i >= 0; i--)
{
var buffer = new List<string>();
var current = arrays[i];
foreach (var head in current)
{
foreach (var tail in last)
{
// Concatenate with the desired space.
buffer.Add(head + " " + tail);
}
}
last = buffer;
}
return (List<string>)last;
}
Could you try this method ?
static List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
for(int x = 0; (x <= wordsOne.Length - 1); ++x)
{
for(int y = 0; (x <= wordsTwo.Length - 1); ++y)
{
combinedWords.Add(string.Format("{0} {1}", wordsOne[x], wordsTwo[y]));
}
}
return combinedWords;
}
Kris

Categories

Resources