C# (String.StartsWith && !String.EndsWith && !String.Contains) using a List - c#

I am a newbie in C#, and I am having problems.
I have 2 List, 2 strings and a getCombinations(string) method that
returns all combinations of a string as List;
How do i validate if a subjectStrings element does not
StartWith && !EndsWith && !Contains (or !StartWith && !EndsWith && Contains, etc.)
for every combinations of startswithString, endswithString and containsString?
Here is my code in StartWith && !EndsWith
(if you want to see it running: http://ideone.com/y8JZkK)
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
List<string> validatedStrings = new List<string>();
List<string> subjectStrings = new List<string>()
{
"con", "cot", "eon", "net", "not", "one", "ten", "toe", "ton",
"cent", "cone", "conn", "cote", "neon", "none", "note", "once", "tone",
"cento", "conte", "nonce", "nonet", "oncet", "tenon", "tonne",
"nocent","concent", "connect"
}; //got a more longer wordlist
string startswithString = "co";
string endswithString = "et";
foreach(var z in subjectStrings)
{
bool valid = false;
foreach(var a in getCombinations(startswithString))
{
foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
if(valid)
{
break;
}
}
if(valid)
{
validatedStrings.Add(z);
}
}
foreach(var a in validatedStrings)
{
Console.WriteLine(a);
}
Console.WriteLine("\nDone");
}
static List<string> getCombinations(string s)
{
//Code that calculates combinations
return Permutations.Permutate(s);
}
}
public class Permutations
{
private static List<List<string>> allCombinations;
private static void CalculateCombinations(string word, List<string> temp)
{
if (temp.Count == word.Length)
{
List<string> clone = temp.ToList();
if (clone.Distinct().Count() == clone.Count)
{
allCombinations.Add(clone);
}
return;
}
for (int i = 0; i < word.Length; i++)
{
temp.Add(word[i].ToString());
CalculateCombinations(word, temp);
temp.RemoveAt(temp.Count - 1);
}
}
public static List<string> Permutate(string str)
{
allCombinations = new List<List<string>>();
CalculateCombinations(str, new List<string>());
List<string> combinations = new List<string>();
foreach(var a in allCombinations)
{
string c = "";
foreach(var b in a)
{
c+=b;
}
combinations.Add(c);
}
return combinations;
}
}
Output:
con
cot
cone
conn
cote <<<
conte <<<
concent
connect
Done
if(z.StartsWith(a) && !z.EndsWith(b))
var b can be "et" and "te", but cote and conte endswith "te",
why it is still added in my validated strings?
Thanks in advance.

z.StartsWith(a) && !z.EndsWith(b)
check below combination
z ="cote"
a ="co"
b ="te"
so z start with "co" and z not end with "te", your condition pass and cote will add to list
i would try as below
var sw =getCombinations(startswithString);
var ew = getCombinations(endswithString);
var result = subjectStrings.Where(z=>
sw.Any(x=>z.StartsWith(x) &&
!ew.Any(y=>z.EndsWith(y))))
.ToList();
DEMO
output :
con
cot
cone
conn
concent
connect

foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
here you are setting valid to true as soon as there is match for !z.EndsWith(b) and you are not traversing the whole list of permutations available.
since "cote" doesn't end with "et" it is a match and valid is set to true and the code breaks.
So that's why "cote" is added to your list of valid strings. So is the case with "conte".
What you want to do is :
List<string> startsWithCombination = getCombinations("co");
List<string> endsWithCombination = getCombinations("et");
foreach (var z in subjectStrings)
{
bool isStartMatchFound = startsWithCombination.Any(b => z.StartsWith(b));
if (isStartMatchFound)
{
bool isEndMatchFound = endsWithCombination.Any(b => z.EndsWith(b));
if (!isEndMatchFound)
{
validatedStrings.Add(z);
}
}
}

Related

Group list of strings by subparts of item

Sorry for the ambiguous title...
I find explaining my issue difficult - let me know if you need to know more.
I've got a list that i'd like to be grouped by part of a string.
This string is also in the list.
This is the complete list, its not static, and will contain different values.
CookieMaker_TransportSettingsManual
CookieMaker_TransportSettingsParameters
Cookie_WrapperSettings
Cookie_WrapperSettingsManual
Cookie_WrapperSettingsParameters
Cookie_ProfileBendSettings
Cookie_ProfileBendSettingsParameters
Cookie_HopperSettings
Cookie_HopperSettingsManual
Cookie_HopperSettingsParameters
Cookie_CutterSettings
Cookie_CutterSettingsManual
Cookie_CutterSettingsParameters
General_SpeedSetting
General_SpeedSettingManual
General_SpeedSettingSettings
General_CalibrationSettings
General_CalibrationSettingsCalibration
Bonbon_Vertical
Bonbon_VerticalAligner
Bonbon_VerticalHopper
Bonbon_VerticalManual
Bonbon_VerticalTransporter
Bonbon_Horizontal
Bonbon_HorizontalHopper
Bonbon_HorizontalManual
Bonbon_HorizontalCookie
Bonbon_HorizontalTransporter
Bonbon_Bonbon
Bonbon_BonbonExhaust
Bonbon_BonbonManual
Bonbon_BonbonSection1
Bonbon_BonbonSection2
Bonbon_BonbonSection3
Bonbon_Compensator
Bonbon_CompensatorCarriage
Bonbon_CompensatorHopper
Bonbon_CompensatorManual
Bonbon_CollectingUnit
Bonbon_CollectingUnitManual
Bonbon_CollectingUnitTransporter
Bonbon_CollectingUnitTubeMaker
CookieMaker_TransportSettings
CookieMaker_TransportSettingsBonbon
CookieMaker_TransportSettingsPandora
The expected result would be a groups like so:
General_SpeedSetting
==> General_SpeedSettingManual
==> General_SpeedSettingSettings
Cookie_WrapperSettings
==> Cookie_WrapperSettingsManual
==> Cookie_WrapperSettingsParameters
The resulting datatype does not matter.
Also i don't mind linq.
Code / fiddle to get up and running quickly;
using System;
public class Program
{
public static void Main()
{
var inputString = "CookieMaker_TransportSettingsManual|CookieMaker_TransportSettingsParameters|Cookie_WrapperSettings|Cookie_WrapperSettingsManual|Cookie_WrapperSettingsParameters|Cookie_ProfileBendSettings|Cookie_ProfileBendSettingsParameters|Cookie_HopperSettings|Cookie_HopperSettingsManual|Cookie_HopperSettingsParameters|Cookie_CutterSettings|Cookie_CutterSettingsManual|Cookie_CutterSettingsParameters|General_SpeedSetting|General_SpeedSettingManual|General_SpeedSettingSettings|General_CalibrationSettings|General_CalibrationSettingsCalibration|Bonbon_Vertical|Bonbon_VerticalAligner|Bonbon_VerticalHopper|Bonbon_VerticalManual|Bonbon_VerticalTransporter|Bonbon_Horizontal|Bonbon_HorizontalHopper|Bonbon_HorizontalManual|Bonbon_HorizontalCookie|Bonbon_HorizontalTransporter|Bonbon_Bonbon|Bonbon_BonbonExhaust|Bonbon_BonbonManual|Bonbon_BonbonSection1|Bonbon_BonbonSection2|Bonbon_BonbonSection3|Bonbon_Compensator|Bonbon_CompensatorCarriage|Bonbon_CompensatorHopper|Bonbon_CompensatorManual|Bonbon_CollectingUnit|Bonbon_CollectingUnitManual|Bonbon_CollectingUnitTransporter|Bonbon_CollectingUnitTubeMaker|CookieMaker_TransportSettings|CookieMaker_TransportSettingsBonbon|CookieMaker_TransportSettingsPandora";
var inputList = inputString.Split('|');
var result = inputList; // Code here ;)
foreach(var r in result)
{ Console.WriteLine(r);}
}
}
https://dotnetfiddle.net/neCUEL
What about something like this?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static List<string> myList = new List<string>(){
"CookieMaker_TransportSettingsManual",
"CookieMaker_TransportSettingsParameters",
"Cookie_WrapperSettings",
"Cookie_WrapperSettingsManual",
"Cookie_WrapperSettingsParameters",
"Cookie_ProfileBendSettings",
"Cookie_ProfileBendSettingsParameters",
"Cookie_HopperSettings",
"Cookie_HopperSettingsManual",
"Cookie_HopperSettingsParameters",
"Cookie_CutterSettings",
"Cookie_CutterSettingsManual",
"Cookie_CutterSettingsParameters",
"General_SpeedSetting",
"General_SpeedSettingManual",
"General_SpeedSettingSettings",
"General_CalibrationSettings",
"General_CalibrationSettingsCalibration",
"Bonbon_Vertical",
"Bonbon_VerticalAligner",
"Bonbon_VerticalHopper",
"Bonbon_VerticalManual",
"Bonbon_VerticalTransporter",
"Bonbon_Horizontal",
"Bonbon_HorizontalHopper",
"Bonbon_HorizontalManual",
"Bonbon_HorizontalCookie",
"Bonbon_HorizontalTransporter",
"Bonbon_Bonbon",
"Bonbon_BonbonExhaust",
"Bonbon_BonbonManual",
"Bonbon_BonbonSection1",
"Bonbon_BonbonSection2",
"Bonbon_BonbonSection3",
"Bonbon_Compensator",
"Bonbon_CompensatorCarriage",
"Bonbon_CompensatorHopper",
"Bonbon_CompensatorManual",
"Bonbon_CollectingUnit",
"Bonbon_CollectingUnitManual",
"Bonbon_CollectingUnitTransporter",
"Bonbon_CollectingUnitTubeMaker",
"CookieMaker_TransportSettings",
"CookieMaker_TransportSettingsBonbon",
"CookieMaker_TransportSettingsPandora"
};
static Dictionary<string, List<string>> results = new Dictionary<string, List<string>>();
//-------------------------------------------------------------------------//
public static void Main()
{
var orderedList = myList.OrderBy(i=>i).ToList();
int i = 0;
while(i < myList.Count){
var prefix = orderedList[i];
results[prefix] = new List<string>();
if(++i >= orderedList.Count) break;
while(orderedList[i].StartsWith(prefix)){
results[prefix].Add(orderedList[i]);
i++;
if(i >= orderedList.Count) {
Print();
return;
}
}//while
}//while
Print();
}//main
//-------------------------------------------------------------------------//
private static void Print(){
foreach (string prefix in results.Keys)
{
Console.WriteLine($"Prefix =>{prefix} - {results[prefix].Count}");
foreach (string result in results[prefix])
{
Console.WriteLine($" ======>{result}");
}//foreach;
}//foreach
}//Print
}//Cls
Fiddle:
https://dotnetfiddle.net/GTI4vV
I'm surprised you accepted a solution that pre-sorted the items. When I tried that, the Bonbon sections got terribly messed up.
My solution is a bit hacky - to get this to work the way I think you want it took a lot of special cases (and fixing off-by-one issues).
The code takes care of this kind of pattern:
CookieMaker_TransportSettingsManual
CookieMaker_TransportSettingsParameters
extracting CookieMaker_TransportSettings and putting both entries under it. It also copes with the fact that you have CookieMaker_TransportSettings at the beginning and the end of the file.
It also handles this:
Bonbon_BonbonSection1
Bonbon_BonbonSection2
Bonbon_BonbonSection3
Figuring that you want the three of those to be part of the Bonbon_Bonbon section and not a new Bonbon_BonbonSection section with three entries (1, 2 and 3).
It also deals with all the Cookie** and Bonbon** sections.
Here's the main code:
//get all the strings from somewhere
var inputStrings = File.ReadAllLines("DataFile.txt");
string lastTitle = null;
var results = new Dictionary<string, List<string>>();
string veryLastItem = string.Empty;
var currentItems = new List<string>();
for (var i = 0; i < inputStrings.Length - 1; ++i)
{
var commonPrefix = FindLongestCommonPrefix(inputStrings[i], inputStrings[i + 1]);
if (string.IsNullOrEmpty(commonPrefix) || (!string.IsNullOrEmpty(lastTitle) && commonPrefix != lastTitle))
{
if (string.IsNullOrEmpty(lastTitle))
{
throw new Exception("This isn't going to work - you need to have at least two common things in a row");
}
if (inputStrings[i].StartsWith(lastTitle) && inputStrings[i] != lastTitle)
{
currentItems.Add(inputStrings[i]);
}
AddResultsToDictionary(results, lastTitle, currentItems);
currentItems = new List<string>();
}
if (commonPrefix != inputStrings[i] &&
((commonPrefix == lastTitle && commonPrefix != inputStrings[i]) ||
(!string.IsNullOrEmpty(commonPrefix) && inputStrings[i].StartsWith(commonPrefix))))
{
currentItems.Add(inputStrings[i]);
}
lastTitle = commonPrefix;
veryLastItem = inputStrings[i + 1];
}
//ok, we're out of the loop:
//add the last item to the current list
currentItems.Add(veryLastItem);
//and add the last set of items to the dictionary
if (lastTitle != null)
{
AddResultsToDictionary(results, lastTitle, currentItems);
}
foreach (var result in results)
{
Debug.WriteLine(result.Key);
foreach (var item in result.Value)
{
Debug.WriteLine($" ==> {item}");
}
}
void AddResultsToDictionary(Dictionary<string, List<string>> dictionary, string s, List<string> list)
{
if (dictionary.TryGetValue(s, out var existingList))
{
existingList.AddRange(list);
}
else
{
dictionary.Add(s, list);
}
}
}
And it calls this function to determine the section headings:
private string FindLongestCommonPrefix(string s1, string s2)
{
var minLen = Math.Min(s1.Length, s2.Length);
for (var i = 0; i < minLen; ++i)
{
if (s1[i] != s2[i])
{
if (i == 0)
{
return string.Empty;
}
else
{
//if the common part is not s1, we need to find the last place where the following
// the last letter of the common part is a lower case letter followed by either
// an underscore or a capital letter
if (i == s1.Length)
{
return s1;
}
if (s1[i] == '_' || s1[i - 1] == '_' || s2[i] == '_' || s2[i - 1] == '_')
{
return string.Empty;
}
for (var j = i; j > 0; --j)
{
if (char.IsLower(s1[j-1]) && (char.IsUpper(s1[j]) /*|| s1[j] == '_'*/))
{
return s1.Substring(0, j);
}
}
//I shouldn't get here, but, if I do
return string.Empty;
}
}
}
//otherwise
return s1.Substring(0, minLen);
}
The result ends up looking like:
CookieMaker_TransportSettings
==> CookieMaker_TransportSettingsManual
==> CookieMaker_TransportSettingsParameters
==> CookieMaker_TransportSettingsBonbon
==> CookieMaker_TransportSettingsPandora
Cookie_WrapperSettings
==> Cookie_WrapperSettingsManual
==> Cookie_WrapperSettingsParameters
Cookie_ProfileBendSettings
==> Cookie_ProfileBendSettingsParameters
Cookie_HopperSettings
==> Cookie_HopperSettingsManual
==> Cookie_HopperSettingsParameters
Cookie_CutterSettings
==> Cookie_CutterSettingsManual
==> Cookie_CutterSettingsParameters
General_SpeedSetting
==> General_SpeedSettingManual
==> General_SpeedSettingSettings
General_CalibrationSettings
==> General_CalibrationSettingsCalibration
Bonbon_Vertical
==> Bonbon_VerticalAligner
==> Bonbon_VerticalHopper
==> Bonbon_VerticalManual
==> Bonbon_VerticalTransporter
Bonbon_Horizontal
==> Bonbon_HorizontalHopper
==> Bonbon_HorizontalManual
==> Bonbon_HorizontalCookie
==> Bonbon_HorizontalTransporter
Bonbon_Bonbon
==> Bonbon_BonbonExhaust
==> Bonbon_BonbonManual
==> Bonbon_BonbonSection1
==> Bonbon_BonbonSection2
==> Bonbon_BonbonSection3
Bonbon_Compensator
==> Bonbon_CompensatorCarriage
==> Bonbon_CompensatorHopper
==> Bonbon_CompensatorManual
Bonbon_CollectingUnit
==> Bonbon_CollectingUnitManual
==> Bonbon_CollectingUnitTransporter
==> Bonbon_CollectingUnitTubeMaker
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
List<string> lines = File.ReadLines(FILENAME).ToList();
lines = lines.OrderBy(x => x).ToList();
List<Group> groups = new List<Group>();
Group group = new Group();
groups.Add(group);
group.basename = lines[0].Trim();
List<List<string>> results = new List<List<string>>();
for (int i = 2; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (!line.StartsWith(group.basename))
{
group = new Group();
groups.Add(group);
group.basename = line;
}
else
{
if(group.values == null) group.values = new List<string>();
group.values.Add(line.Substring(group.basename.Length));
}
}
}
}
public class Group
{
public string basename { get; set; }
public List<string> values { get; set; }
}
}

C# arbitrary nested Lists

In Python I can convert a binary tree structure to an arbitrary nested List:
great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
[great, [gr, [g, r], eat, [e, at, [a, t]]]
Is there a way to build an arbitrary nested List in C#?
EDIT: I took a BinaryTree<T> class from MSDN docs as a base class for my custom StrBinaryTree class. Method FormTree is doing a job for creating a tree structure from a string:
public class StrBinaryTree : BinaryTree<string>
{
public StrBinaryTree(string data)
{
if (data.Length == 0)
{
base.Root = null;
base.Count = 0;
}
else
{
base.Root = new BinaryTreeNode<string>();
base.Root.Data = data;
base.Count = 1;
}
}
public void FormTree(BinaryTreeNode<string> node)
{
var subLength = node.Data.Length / 2;
if (subLength == 0)
return;
node.Left = new BinaryTreeNode<string>(node.Data.Substring(0, subLength));
node.Right = new BinaryTreeNode<string>(node.Data.Substring(subLength));
base.Count += 2;
FormTree(node.Left);
FormTree(node.Right);
}
...}
I would use recursion to go through the tree. Since you didn't told us the type of the tree we cannot provide you c# sample code.
But it would be something like this:
void List<Object> GetNestedListFromTree(Tree tree, List<Object> list = null)
{
List<Object> curList;
if (!tree.HasChildNodes)
return list;
else
{
if (list==null)
{
list = new List<Object>;
curList = list;
}
else
{
curList = new List<Object>;
list.Add(curList);
}
foreach(node in tree.ChildNodes)
{
curList.Add(node.Name);
curList.Add(GetNestedListFromTree(node.GetSubtree, curList));
}
return curList;
}
}
This isn't tested because I don't know your tree but yeah ... It should work if your tree can provide the needed functionality.
Try this solution
public static List<object> Solve(string input, List<object> list = null)
{
if (list == null)
return Solve(input, new List<object> { input });
if (input.Length > 1)
{
var middle = input.Length / 2;
var first = input.Substring(0, middle);
var second = input.Substring(middle);
var innerList = new List<object>();
list.Add(innerList);
foreach (var side in new[] { first, second })
{
innerList.Add(side);
Solve(side, innerList);
}
}
return list;
}
public static void Show(object input)
{
if (!(input is string))
{
Console.Write("[");
var list = input as List<object>;
foreach (var item in list)
{
Show(item);
if (item != list.Last())
Console.Write(", ");
}
Console.Write("]");
}
else
Console.Write(input);
}
Usage:
var result = Solve("great");
Show(result);//[great, [gr, [g, r], eat, [e, at, [a, t]]]]
Approximate code for BinaryTreeNode:
public static BinaryTreeNode<string> Solve(BinaryTreeNode<string> node)
{
if(node.Data.Length > 1)
{
var middle = node.Data.Length / 2;
var left = node.Data.Substring(0, middle);
var right = node.Data.Substring(middle);
node.Left = Solve(new BinaryTreeNode<string>(left));
node.Right = Solve(new BinaryTreeNode<string>(right));
}
return node;
}
Usage:
var result = Solve(new BinaryTreeNode<string>("great"));
Try this:
public Tree<string> Build(string text)
{
var tree = new Tree<string>() { Value = text };
if (text.Length > 1)
{
tree.Add(Build(text.Substring(0, text.Length / 2)));
tree.Add(Build(text.Substring(text.Length / 2)));
}
return tree;
}
public class Tree<T> : List<Tree<T>>
{
public T Value;
public override string ToString()
{
var r = $"\"{this.Value}\"";
if (this.Any())
{
r += $" [{String.Join(", ", this.Select(t => t.ToString()))}]";
}
return r;
}
}
When I run Build("great") I get:
"great" ["gr" ["g", "r"], "eat" ["e", "at" ["a", "t"]]]

Create a list of all permutation from different lists [duplicate]

This one should not be too hard but my mind seems to be having a stack overflow (huehue). I have a series of Lists and I want to find all permutations they can be ordered in. All of the lists have different lengths.
For example:
List 1: 1
List 2: 1, 2
All permutations would be:
1, 1
1, 2
In my case I don't switch the numbers around. (For example 2, 1)
What is the easiest way to write this?
I can't say if the following is the easiest way, but IMO it's the most efficient way. It's basically a generalized version of the my answer to the Looking at each combination in jagged array:
public static class Algorithms
{
public static IEnumerable<T[]> GenerateCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
{
var result = new T[input.Count];
var indices = new int[input.Count];
for (int pos = 0, index = 0; ;)
{
for (; pos < result.Length; pos++, index = 0)
{
indices[pos] = index;
result[pos] = input[pos][index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index >= input[pos].Count);
}
}
}
You can see the explanation in the linked answer (shortly it's emulating nested loops). Also since for performace reasons it yields the internal buffer w/o cloning it, you need to clone it if you want store the result for later processing.
Sample usage:
var list1 = new List<int> { 1 };
var list2 = new List<int> { 1, 2 };
var lists = new[] { list1, list2 };
// Non caching usage
foreach (var combination in lists.GenerateCombinations())
{
// do something with the combination
}
// Caching usage
var combinations = lists.GenerateCombinations().Select(c => c.ToList()).ToList();
UPDATE: The GenerateCombinations is a standard C# iterator method, and the implementation basically emulates N nested loops (where N is the input.Count) like this (in pseudo code):
for (int i0 = 0; i0 < input[0].Count; i0++)
for (int i1 = 0; i1 < input[1].Count; i1++)
for (int i2 = 0; i2 < input[2].Count; i2++)
...
for (int iN-1 = 0; iN-1 < input[N-1].Count; iN-1++)
yield { input[0][i0], input[1][i1], input[2][i2], ..., input[N-1][iN-1] }
or showing it differently:
for (indices[0] = 0; indices[0] < input[0].Count; indices[0]++)
{
result[0] = input[0][indices[0]];
for (indices[1] = 0; indices[1] < input[1].Count; indices[1]++)
{
result[1] = input[1][indices[1]];
// ...
for (indices[N-1] = 0; indices[N-1] < input[N-1].Count; indices[N-1]++)
{
result[N-1] = input[N-1][indices[N-1]];
yield return result;
}
}
}
Nested loops:
List<int> listA = (whatever), listB = (whatever);
var answers = new List<Tuple<int,int>>;
for(int a in listA)
for(int b in listB)
answers.add(Tuple.create(a,b));
// do whatever with answers
Try this:
Func<IEnumerable<string>, IEnumerable<string>> combine = null;
combine = xs =>
xs.Skip(1).Any()
? xs.First().SelectMany(x => combine(xs.Skip(1)), (x, y) => String.Format("{0}{1}", x, y))
: xs.First().Select(x => x.ToString());
var strings = new [] { "AB", "12", "$%" };
foreach (var x in combine(strings))
{
Console.WriteLine(x);
}
That gives me:
A1$
A1%
A2$
A2%
B1$
B1%
B2$
B2%
I made the following IEnumerable<IEnumerable<TValue>> class to solve this problem which allows use of generic IEnumerable's and whose enumerator returns all permutations of the values, one from each inner list. It can be conventiently used directly in a foreach loop.
It's a variant of Michael Liu's answer to IEnumerable and Recursion using yield return
I've modified it to return lists with the permutations instead of the single values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Permutation
{
public class ListOfListsPermuter<TValue> : IEnumerable<IEnumerable<TValue>>
{
private int count;
private IEnumerable<TValue>[] listOfLists;
public ListOfListsPermuter(IEnumerable<IEnumerable<TValue>> listOfLists_)
{
if (object.ReferenceEquals(listOfLists_, null))
{
throw new ArgumentNullException(nameof(listOfLists_));
}
listOfLists =listOfLists_.ToArray();
count = listOfLists.Count();
for (int i = 0; i < count; i++)
{
if (object.ReferenceEquals(listOfLists[i], null))
{
throw new NullReferenceException(string.Format("{0}[{1}] is null.", nameof(listOfLists_), i));
}
}
}
// A variant of Michael Liu's answer in StackOverflow
// https://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return
public IEnumerator<IEnumerable<TValue>> GetEnumerator()
{
TValue[] currentList = new TValue[count];
int level = 0;
var enumerators = new Stack<IEnumerator<TValue>>();
IEnumerator<TValue> enumerator = listOfLists[level].GetEnumerator();
try
{
while (true)
{
if (enumerator.MoveNext())
{
currentList[level] = enumerator.Current;
level++;
if (level >= count)
{
level--;
yield return currentList;
}
else
{
enumerators.Push(enumerator);
enumerator = listOfLists[level].GetEnumerator();
}
}
else
{
if (level == 0)
{
yield break;
}
else
{
enumerator.Dispose();
enumerator = enumerators.Pop();
level--;
}
}
}
}
finally
{
// Clean up in case of an exception.
enumerator?.Dispose();
while (enumerators.Count > 0)
{
enumerator = enumerators.Pop();
enumerator.Dispose();
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
You can use it directly in a foreach like this:
public static void Main(string[] args)
{
var listOfLists = new List<List<string>>()
{
{ new List<string>() { "A", "B" } },
{ new List<string>() { "C", "D" } }
};
var permuter = new ListOfListsPermuter<string>(listOfLists);
foreach (IEnumerable<string> item in permuter)
{
Console.WriteLine("{ \"" + string.Join("\", \"", item) + "\" }");
}
}
The output:
{ "A", "C" }
{ "A", "D" }
{ "B", "C" }
{ "B", "D" }

Sort Array on on Value Difference

I Have An Array,for example
string[] stArr= new string[5] { "1#3", "19#24", "10#12", "13#18", "20#21" };
i want to sort this array on
3-1=2;
24-19=5;
12-10=2;
18-13=5;
21-20=1;
and the sorting result should be like
string[] stArr= new string[5] { "20#21", "1#3", "10#12", "13#18", "20#21" };
I have to find the solution for all possible cases.
1>length of the array is not fixed(element in the array)
2>y always greater than x e.g x#y
3> i can not use list
You can use LINQ:
var sorted = stArr.OrderBy(s => s.Split('#')
.Select(n => Int32.Parse(n))
.Reverse()
.Aggregate((first,second) => first - second));
For Your Case:
stArr = stArr.OrderBy(s => s.Split('#')
.Select(n => Int32.Parse(n))
.Reverse()
.Aggregate((first,second) => first - second)).ToArray();
try this
string[] stArr = new string[5] { "1#3", "19#24", "10#12", "13#18", "20#21" };
Array.Sort(stArr, new Comparison<string>(compare));
int compare(string z, string t)
{
var xarr = z.Split('#');
var yarr = t.Split('#');
var x1 = int.Parse(xarr[0]);
var y1 = int.Parse(xarr[1]);
var x2 = int.Parse(yarr[0]);
var y2 = int.Parse(yarr[1]);
return (y1 - x1).CompareTo(y2 - x2);
}
Solving this problem is identical to solving any other sorting problem where the order is to be specified by your code - you have to write a custom comparison method, and pass it to the built-in sorter.
In your situation, it means writing something like this:
private static int FindDiff(string s) {
// Split the string at #
// Parse both sides as int
// return rightSide-leftSide
}
private static int CompareDiff(string a, string b) {
return FindDiff(a).CompareTo(FindDiff(b));
}
public static void Main() {
... // Prepare your array
string[] stArr = ...
Array.Sort(stArr, CompareDiff);
}
This approach uses Array.Sort overload with the Comparison<T> delegate implemented in the CompareDiff method. The heart of the solution is the FindDiff method, which takes a string, and produces a numeric value which must be used for comparison.
you can try the following ( using traditional way)
public class Program
{
public static void Main()
{
string[] strArr= new string[5] { "1#3", "19#24", "10#12", "13#18", "20#21" };
var list = new List<Item>();
foreach(var item in strArr){
list.Add(new Item(item));
}
strArr = list.OrderBy(t=>t.Sort).Select(t=>t.Value).ToArray();
foreach(var item in strArr)
Console.WriteLine(item);
}
}
public class Item
{
public Item(string str)
{
var split = str.Split('#');
A = Convert.ToInt32(split[0]);
B = Convert.ToInt32(split[1]);
}
public int A{get; set;}
public int B{get; set;}
public int Sort { get { return Math.Abs(B - A);}}
public string Value { get { return string.Format("{0}#{1}",B,A); }}
}
here a working demo
hope it will help you
Without LINQ and Lists :) Old School.
static void Sort(string [] strArray)
{
try
{
string[] order = new string[strArray.Length];
string[] sortedarray = new string[strArray.Length];
for (int i = 0; i < strArray.Length; i++)
{
string[] values = strArray[i].ToString().Split('#');
int index=int.Parse(values[1].ToString()) - int.Parse(values[0].ToString());
order[i] = strArray[i].ToString() + "," + index;
}
for (int i = 0; i < order.Length; i++)
{
string[] values2 = order[i].ToString().Split(',');
if (sortedarray[int.Parse(values2[1].ToString())-1] == null)
{
sortedarray[int.Parse(values2[1].ToString())-1] = values2[0].ToString();
}
else
{
if ((int.Parse(values2[1].ToString())) >= sortedarray.Length)
{
sortedarray[(int.Parse(values2[1].ToString())-1) - 1] = values2[0].ToString();
}
else if ((int.Parse(values2[1].ToString())) < sortedarray.Length)
{
sortedarray[(int.Parse(values2[1].ToString())-1) + 1] = values2[0].ToString();
}
}
}
for (int i = 0; i < sortedarray.Length; i++)
{
Console.WriteLine(sortedarray[i]);
}
Console.Read();
}
catch (Exception ex)
{
throw;
}
finally
{
}

Connect element in distinct array using recursion

if I have two array
A:[A,B]
B:[1,2,3]
how can I create a string List like [A_1, A_2, A_3, B_1, B_2, B_3]
the number of array is not regular, it's maybe have 3 more
A:[A,B]
B:[1,2,3]
C:[w,x,y,z]
D:[m,n]
E:[p,q,r]
can I use recursive to solve it?
So, we define a functions Mergethat takes lists of list of stings and merges them into the string enumerable you want
static void Main(string[] args)
{
var a = new[] { "A", "B" };
var b = new[] { "1", "2", "3" };
var c = new[] { "x", "y", "z", "w" };
var result = Merge(a, b, c);
foreach (var r in result)
{
Console.WriteLine(r);
}
}
public static IList<string> Merge(params IEnumerable<string>[] lists)
{
return Merge((IEnumerable<IEnumerable<string>>) lists);
}
public static IList<string> Merge(IEnumerable<IEnumerable<string>> lists)
{
var retval = new List<string>();
var first = lists.FirstOrDefault();
if (first != null)
{
var result = Merge(lists.Skip(1));
if (result.Count > 0)
{
foreach (var x in first)
{
retval.AddRange(result.Select(y => string.Format("{0}_{1}", x, y)));
}
}
else
{
retval.AddRange(first);
}
}
return retval;
}
we can also improve this, if you use Lists as inputs
public static IList<string> Merge(params IList<string>[] lists)
{
return Merge((IList<IList<string>>) lists);
}
public static IList<string> Merge(IList<IList<string>> lists, int offset = 0)
{
if (offset >= lists.Count)
return new List<string>();
var current = lists[offset];
if (offset + 1 == lists.Count) // last entry in lists
return current;
var retval = new List<string>();
var merged = Merge(lists, offset + 1);
foreach (var x in current)
{
retval.AddRange(merged.Select(y => string.Format("{0}_{1}", x, y)));
}
return retval;
}
This is simple iterating over n-ary dimension - no need for recursion for that, just array to store indexes.
static void Iterate(int[] iterators, ArrayList[] arrays) {
for (var j = iterators.Length - 1; j >= 0; j--) {
iterators[j]++;
if (iterators[j] == arrays[j].Count) {
if (j == 0) {
break;
}
iterators[j] = 0;
} else {
break;
}
}
}
static IList<string> Merge(ArrayList[] arrays) {
List<string> result = new List<string>();
int[] iterators = new int[arrays.Length];
while (iterators[0] != arrays[0].Count) {
var builder = new StringBuilder(20);
for(var index = 0; index < arrays.Length; index++) {
if (index > 0) {
builder.Append("_");
}
builder.Append(arrays[index][iterators[index]]);
}
result.Add(builder.ToString());
Iterate(iterators, arrays);
}
return result;
}
static void Main(string[] args) {
var list1 = new ArrayList();
var list2 = new ArrayList();
var list3 = new ArrayList();
list1.Add(1);
list1.Add(2);
list2.Add("a");
list2.Add("b");
list3.Add("x");
list3.Add("y");
list3.Add("z");
var result = Merge(new[] { list1, list2, list3 });
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace arrconn {
class Program {
static string[] conn(params Array[] arrs) {
if(arrs.Length == 0) return new string[0];
if(arrs.Length == 1) {
string[] result = new string[arrs[0].Length];
for(int i = 0; i < result.Length; i++)
result[i] = arrs[0].GetValue(i).ToString();
return result; }
else {
string[] result = new string[arrs[0].Length*arrs[1].Length];
for(int i = 0; i < arrs[0].Length; i++)
for(int j = 0; j < arrs[1].Length; j++)
result[i*arrs[1].Length+j] = string.Format("{0}_{1}", arrs[0].GetValue(i), arrs[1].GetValue(j));
if(arrs.Length == 2) return result;
Array[] next = new Array[arrs.Length-1];
next[0] = result; Array.Copy(arrs, 2, next, 1, next.Length-1);
return conn(next);
}
}
static void Main(string[] args) {
foreach(string s in conn(
new string[] { "A", "B" },
new int[] { 1, 2, 3 },
new string[] { "x" },
new string[] { "$", "%", "#" }))
Console.WriteLine(s);
Console.Read();
}
}
}
I guess your input are like this:
var A = ["A","B"];
var B = [1,2,3];
var C = ["x","y","z","w"];
And what you want to obtain is:
var result = ["A_1_x", "A_1_y",...
"A_2_x", "A_2_y",...
"A_3_x", "A_3_y",...
"B_1_x", "B_1_y",...
...
..., "B_3_z", "B_3_w"];
We'll be working with IEnumerable as it will simplify the work for us and give us access to the yield keyword.
First, let's take care of the case where we only concataining two collections:
IEnumerable<string> ConcatEnumerables(IEnumerable<object> first, IEnumerable<object> second)
{
foreach (var x in first)
{
foreach (var y in second)
{
yield return x.ToString() + "_" + y.ToString();
}
}
}
Then we can recursively takle any number of collections:
IEnumerable<string> ConcatEnumerablesRec(IEnumerable<IEnumerable<object>> enums)
{
//base cases
if(!enums.Any())
{
return Enumerable.Empty<string>();
}
if (enums.Count() == 1)
{
return enums.First().Select(o => o.ToString());
}
//recursively solve the problem
return ConcatEnumerables(enums.First(), ConcatEnumerablesRec(enums.Skip(1));
}
Now you just need to call ToArray on the result if you really need an array as your output.
string[] Concatenator(params object[][] parameters)
{
return ConcatEnumerablesRec(parameters).ToArray();
}
This should do the trick. Note that the input sequences do not have to be arrays - they can be any type that implements IEnumerable<>.
Also note that we have to case sequences of value types to sequences of <object> so that they are assignable to IEnumerable<object>.
Here's the compilable Console app demo code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
internal static class Program
{
static void Main()
{
string[] a = {"A", "B", "C", "D"};
var b = Enumerable.Range(1, 3); // <-- See how it doesn't need to be an array.
char[] c = {'X', 'Y', 'Z'};
double[] d = {-0.1, -0.2};
var sequences = new [] { a, b.Cast<object>(), c.Cast<object>(), d.Cast<object>() };
Console.WriteLine(string.Join("\n", Combine("", sequences)));
}
public static IEnumerable<string> Combine(string prefix, IEnumerable<IEnumerable<object>> sequences)
{
foreach (var item in sequences.First())
{
string current = (prefix == "") ? item.ToString() : prefix + "_" + item;
var remaining = sequences.Skip(1);
if (!remaining.Any())
{
yield return current;
}
else
{
foreach (var s in Combine(current, remaining))
yield return s;
}
}
}
}
}

Categories