How to split a item in array to two item with conditional? - c#

I have an example above.
Have array like:
array[0] = TODO 06:15PMJoin Michael
array[1] = WakeUp
array[2] = Going to schools
I want it become like:
array[0] = TODO 06:15PM
array[1] = Join Michael
array[2] = WakeUp
array[3] = Going to schools
In this example, I split item have content TODO 06:15PMJoin Michael to new two item.
Have two separate questions here:
How to create a role for creating a new item in an array?
I tried with my code:
var splitList = words.SelectMany(x => x.Contains("AM") || x.Contains("PM"))
But I don't know how to split from text AM or PM to the new item in arrays.

You can try finding AM/PM and get substrings:
String[] array = new String[] {
"TODO 06:15PMJoin Michael",
"WakeUp",
"Going to schools"
};
var result = array
.SelectMany(line => {
int p = line.IndexOf("AM");
if (p >= 0)
return new String[] {
line.Substring(0, p + "AM".Length),
line.Substring(p + "AM".Length) };
p = line.IndexOf("PM");
if (p >= 0)
return new String[] {
line.Substring(0, p + "PM".Length),
line.Substring(p + "PM".Length) };
return new String[] { line };
}
);
//.ToArray(); // if you want to have array representation
// Test
Console.Write(String.Join(Environment.NewLine, result));

You can also try this:
string[] array = new string[] {"TODO 06:15PMJoin Michael",
"WakeUp",
"Going to schools"};
string[] SplitArray(string[] array)
{
List<string> returnArray = new List<string>();
foreach (string item in array)
{
int index = GetIndex(item);
if (index >= 0)
{
string s1 = item.Substring(0, index + 2);
string s2 = item.Substring(index + 2);
returnArray.Add(s1);
returnArray.Add(s2);
}
else
{
returnArray.Add(item);
}
}
return returnArray.ToArray();
}
int GetIndex(string s)
{
int index = GetIndexOf(s, "AM");
if (index == -1)
{
index = GetIndexOf(s, "PM");
}
return index;
}
int GetIndexOf(string s, string delim)
{
int index = -1;
int tempIndex = 0;
do
{
tempIndex = s.IndexOf(delim, tempIndex);
if (tempIndex > 0)
{
if (char.IsDigit(s[tempIndex-1]))
{
index = tempIndex;
break;
}
}
}
while(tempIndex >= 0);
return index;
}

Related

String Split to String Array without seperator

Code:
string animals = "cat98dog75";
What i try to achieve :
string a = "cat98";
string b = "dog75";
Question :
How do i split the string using some range delimiter?
example :
animals.split();
I suggest matching with a help of regular expressions:
using System.Text.RegularExpressions;
...
string animals = "cat98dog75";
string[] items = Regex
.Matches(animals, "[a-zA-Z]+[0-9]*")
.OfType<Match>()
.Select(match => match.Value)
.ToArray();
string a = items[0];
string b = items[1];
Concole.Write(string.Join(", ", items));
Outcome:
cat98, dog75
In case you want to split the initial string by equal size chunks:
int size = 5;
string[] items = Enumerable
.Range(0, animals.Length / size + (animals.Length % size > 0 ? 1 : 0))
.Select(index => (index + 1) * size <= animals.Length
? animals.Substring(index * size, size)
: animals.Substring(index * size))
.ToArray();
string a = items[0];
string b = items[1];
This might do the trick for you
string animals = "cat98dog75";
string[] DiffAnimals = Regex.Split(animals, "(?<=[0-9]{2})")
.Where(s => s != String.Empty) //Just to Remove Empty Entries.
.ToArray();
If you want to split the name of the animal and number, try following..
I know its too long....
private static void SplitChars()
{
string animals = "cat98dog75";
Dictionary<string, string> dMyobject = new Dictionary<string, string>();
string sType = "",sCount = "";
bool bLastOneWasNum = false;
foreach (var item in animals.ToCharArray())
{
if (char.IsLetter(item))
{
if (bLastOneWasNum)
{
dMyobject.Add(sType, sCount);
sType = ""; sCount = "";
bLastOneWasNum = false;
}
sType = sType + item;
}
else if (char.IsNumber(item))
{
bLastOneWasNum = true;
sCount = sCount + item;
}
}
dMyobject.Add(sType, sCount);
foreach (var item in dMyobject)
{
Console.WriteLine(item.Key + "- " + item.Value);
}
}
You will get output as
cat - 98
dog - 75
Basically, you are getting type and numbers so if you want to use the count, you don't need to split again...

Iterating non-square (sort of) matrix

I have a dictionary like this (sample data thus it doesn't make sense):
Dictionary<char, string[]> codes = new Dictionary<char, string[]>();
string[] is an array of possible replacements for the Dictionary's key.
Filling up the dictionary with some sample data...
codes.Add("A", new string[] {"噅噅", "裧", "頖", "11"});
codes.Add("B", new string[] {"垥", "2", "鉠"});
codes.Add("C", new string[] {"33", "韎"});
codes.Add("D", new string[] {"櫋", "緟", "嘕", "鈖", "灡", "犅"});
...
codes.Add("T", new string[] {"濇", "汫", "岕", "5"});
...
Now lets "encode" the following word:
char[] charArray = "act".ToCharArray();
foreach (char c in charArray) {
string[] replacements = codes[c].Where(x => !String.IsNullOrEmpty(x)).ToArray();//removing empty elements
...
}
I cannot wrap my head now on what to do next, I want to have a list of all possible combinations, it should return a list like this (for the word "act"):
噅噅韎5
裧33濇
裧33汫
裧33岕
裧335
裧韎濇
裧韎汫
裧韎岕
...
Can't show all combinations because of stackoverflow's spam filter...
The post title is misleading. If I understand correctly, you want to generate all the combinations using the codes as input char replacements.
I have answered a similar question (String combinations with multi-character replacement), however due to string[] part I cannot reuse directly the handy code from Looking at each combination in jagged array, so instead I'll just utilize the same algorithm for your case:
public static class Algorithms
{
public static IEnumerable<string> GetCombinations(this string input, Dictionary<char, string[]> replacements)
{
var map = new string[input.Length][];
for (int i = 0; i < map.Length; i++)
{
var c = input[i];
string[] r;
map[i] = replacements.TryGetValue(c, out r)
&& (r = r.Where(s => !string.IsNullOrEmpty(s)).ToArray()).Length > 0 ?
r : new string[] { c.ToString() };
}
int maxLength = map.Sum(output => output.Max(s => s.Length));
var buffer = new char[maxLength];
int length = 0;
var indices = new int[input.Length];
for (int pos = 0, index = 0; ;)
{
for (; pos < input.Length; pos++, index = 0)
{
indices[pos] = index;
foreach (var c in map[pos][index])
buffer[length++] = c;
}
yield return new string(buffer, 0, length);
do
{
if (pos == 0) yield break;
index = indices[--pos];
length -= map[pos][index].Length;
}
while (++index >= map[pos].Length);
}
}
}
Test:
var codes = new Dictionary<char, string[]>();
codes.Add('A', new string[] { "噅噅", "裧", "頖", "11" });
codes.Add('B', new string[] { "垥", "2", "鉠" });
codes.Add('C', new string[] { "33", "韎" });
codes.Add('D', new string[] { "櫋", "緟", "嘕", "鈖", "灡", "犅" });
//...
codes.Add('T', new string[] { "濇", "汫", "岕", "5" });
//...
var test = "ACT".GetCombinations(codes).ToList();

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;
}
}
}
}
}

Array.Sort for strings with numbers [duplicate]

This question already has answers here:
Natural Sort Order in C#
(18 answers)
Closed 8 years ago.
I have sample codes below:
List<string> test = new List<string>();
test.Add("Hello2");
test.Add("Hello1");
test.Add("Welcome2");
test.Add("World");
test.Add("Hello11");
test.Add("Hello10");
test.Add("Welcome0");
test.Add("World3");
test.Add("Hello100");
test.Add("Hello20");
test.Add("Hello3");
test.Sort();
But what happen is, the test.Sort will sort the array to:
"Hello1",
"Hello10",
"Hello100",
"Hello11",
"Hello2",
"Hello20",
"Hello3",
"Welcome0",
"Welcome2",
"World",
"World3"
Is there any way to sort them so that the string will have the correct number order as well?
(If there is no number at the end of the string, that string will always go first - after the alphabetical order)
Expected output:
"Hello1",
"Hello2",
"Hello3",
"Hello10",
"Hello11",
"Hello20",
"Hello100",
"Welcome0",
"Welcome2",
"World",
"World3"
Here is a one possible way using LINQ:
var orderedList = test
.OrderBy(x => new string(x.Where(char.IsLetter).ToArray()))
.ThenBy(x =>
{
int number;
if (int.TryParse(new string(x.Where(char.IsDigit).ToArray()), out number))
return number;
return -1;
}).ToList();
Create an IComparer<string> implementation. The advantage of doing it this way over the LINQ suggestions is you now have a class that can be passed to anything that needs to sort in this fashion rather that recreating that linq query in other locations.
This is specific to your calling a sort from a LIST. If you want to call it as Array.Sort() please see version two:
List Version:
public class AlphaNumericComparer : IComparer<string>
{
public int Compare(string lhs, string rhs)
{
if (lhs == null)
{
return 0;
}
if (rhs == null)
{
return 0;
}
var s1Length = lhs.Length;
var s2Length = rhs.Length;
var s1Marker = 0;
var s2Marker = 0;
// Walk through two the strings with two markers.
while (s1Marker < s1Length && s2Marker < s2Length)
{
var ch1 = lhs[s1Marker];
var ch2 = rhs[s2Marker];
var s1Buffer = new char[s1Length];
var loc1 = 0;
var s2Buffer = new char[s2Length];
var loc2 = 0;
// Walk through all following characters that are digits or
// characters in BOTH strings starting at the appropriate marker.
// Collect char arrays.
do
{
s1Buffer[loc1++] = ch1;
s1Marker++;
if (s1Marker < s1Length)
{
ch1 = lhs[s1Marker];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(s1Buffer[0]));
do
{
s2Buffer[loc2++] = ch2;
s2Marker++;
if (s2Marker < s2Length)
{
ch2 = rhs[s2Marker];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(s2Buffer[0]));
// If we have collected numbers, compare them numerically.
// Otherwise, if we have strings, compare them alphabetically.
string str1 = new string(s1Buffer);
string str2 = new string(s2Buffer);
int result;
if (char.IsDigit(s1Buffer[0]) && char.IsDigit(s2Buffer[0]))
{
var thisNumericChunk = int.Parse(str1);
var thatNumericChunk = int.Parse(str2);
result = thisNumericChunk.CompareTo(thatNumericChunk);
}
else
{
result = str1.CompareTo(str2);
}
if (result != 0)
{
return result;
}
}
return s1Length - s2Length;
}
}
call like so:
test.sort(new AlphaNumericComparer());
//RESULT
Hello1
Hello2
Hello3
Hello10
Hello11
Hello20
Hello100
Welcome0
Welcome2
World
World3
Array.sort version:
Create class:
public class AlphaNumericComparer : IComparer
{
public int Compare(object x, object y)
{
string s1 = x as string;
if (s1 == null)
{
return 0;
}
string s2 = y as string;
if (s2 == null)
{
return 0;
}
int len1 = s1.Length;
int len2 = s2.Length;
int marker1 = 0;
int marker2 = 0;
// Walk through two the strings with two markers.
while (marker1 < len1 && marker2 < len2)
{
var ch1 = s1[marker1];
var ch2 = s2[marker2];
// Some buffers we can build up characters in for each chunk.
var space1 = new char[len1];
var loc1 = 0;
var space2 = new char[len2];
var loc2 = 0;
// Walk through all following characters that are digits or
// characters in BOTH strings starting at the appropriate marker.
// Collect char arrays.
do
{
space1[loc1++] = ch1;
marker1++;
if (marker1 < len1)
{
ch1 = s1[marker1];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
do
{
space2[loc2++] = ch2;
marker2++;
if (marker2 < len2)
{
ch2 = s2[marker2];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
// If we have collected numbers, compare them numerically.
// Otherwise, if we have strings, compare them alphabetically.
var str1 = new string(space1);
var str2 = new string(space2);
var result = 0;
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
{
var thisNumericChunk = int.Parse(str1);
var thatNumericChunk = int.Parse(str2);
result = thisNumericChunk.CompareTo(thatNumericChunk);
}
else
{
result = str1.CompareTo(str2);
}
if (result != 0)
{
return result;
}
}
return len1 - len2;
}
}
Call like so:
This time test is an array instead of a list.
Array.sort(test, new AlphaNumericComparer())
You can use LINQ combined with regex to ensure that you use only numbers that occur at the end of the string for your secondary ordering
test
.Select(t => new{match = Regex.Match(t, #"\d+$"), val = t})
.Select(x => new{sortVal = x.match.Success
?int.Parse(x.match.Value)
:-1,
val = x.val})
.OrderBy(x => x.val)
.ThenBy(x => x.sortVal)
.Select(x => x.val)
.ToList()

Array not working when more than one value is provided

This is my code for my Page_Load:
string _group_array = Group_Array.Get_Group_Array(3);
string[] groups = new string[] { _group_array };
foreach (string group in groups)
{
GridView grdv = new GridView();
grdv.DataSource = Connections.isp_GET_GRIDVIEW_DATA("STDNG", group, "", "");
grdv.DataBind();
gridview_holder.Controls.Add(grdv);
}
And this is the code for my Group_Array class:
public static String Get_Group_Array(int count)
{
string _cs_group_array = "";
if(count == 1)
{
_cs_group_array = "A";
}
else if(count == 2)
{
_cs_group_array = "A, B";
}
else if (count == 3)
{
_cs_group_array = "A, B, C";
}
return _cs_group_array;
}
My issue is that when my count is greater than 1, my groups does not work. Any ideas as to why?
Problem1 : you are not seperating the group string _group_array using comma as delimiter .
Solution1 : you need to split the group string _group_array using comma as delimiter.
Note: you can use Split() function for Splitting the string.
Replace This:
string[] groups = new string[] { _group_array };
With This:
string[] groups = _group_array.Split(',');
Problem 2: you have spaces between the strings.
Solution 2: you need to remove the spaces between the strings.
Replace This:
else if(count == 2)
{
_cs_group_array = "A, B";
}
else if (count == 3)
{
_cs_group_array = "A, B, C";
}
With This:
else if(count == 2)
{
_cs_group_array = "A,B";
}
else if (count == 3)
{
_cs_group_array = "A,B,C";
}
Complete Code:
string _group_array = Group_Array.Get_Group_Array(3);
string[] groups = _group_array.Split(',');
foreach (string group in groups)
{
GridView grdv = new GridView();
grdv.DataSource = Connections.isp_GET_GRIDVIEW_DATA("STDNG", group, "", "");
grdv.DataBind();
gridview_holder.Controls.Add(grdv);
}
public static String Get_Group_Array(int count)
{
string _cs_group_array = "";
if(count == 1)
{
_cs_group_array = "A";
}
else if(count == 2)
{
_cs_group_array = "A,B";
}
else if (count == 3)
{
_cs_group_array = "A,B,C";
}
return _cs_group_array;
}
I'm going to suggest what I think is a cleaner approach:
string[] groups = new [] { "A", "B", "C" }.Take(count);
Your Get_Group_Array method always returns one string, not a string array.That's why your foreach is executing only once because your groups array has only one element. According to your code you can change your method like this:
public static string[] Get_Group_Array(int count)
{
string _cs_group_array = "";
if(count == 1)
{
_cs_group_array = "A";
}
else if(count == 2)
{
_cs_group_array = "A, B";
}
else if (count == 3)
{
_cs_group_array = "A, B, C";
}
return _cs_group_array.Split(',');
}
Then call it:
string[] groups = Group_Array.Get_Group_Array(3);
If you want to make it better:
public static string[] Get_Group_Array(int count)
{
string[] chars = new string[count];
for (int i = 0; i < count; i++)
{
chars[i] = ((char) i + 65).ToString();
}
return chars;
}

Categories