how to get all combination of an arraylist? - c#

I have an arraylist of strings "abcde"
I want to a method to return another arraylist with all the possible combination of a given arraylist (ex:ab,ac,ad...) in C#
anyone knows a simple method?
NB: all possible combinations of length 2, and would be better if the length is variable(can be changed)

Pertaining your comment requiring combinations of length two:
string s = "abcde";
var combinations = from c in s
from d in s.Remove(s.IndexOf(c), 1)
select new string(new[] { c, d });
foreach (var combination in combinations) {
Console.WriteLine(combination);
}
Responding to your edit for any length:
static IEnumerable<string> GetCombinations(string s, int length) {
Guard.Against<ArgumentNullException>(s == null);
if (length > s.Length || length == 0) {
return new[] { String.Empty };
if (length == 1) {
return s.Select(c => new string(new[] { c }));
}
return from c in s
from combination in GetCombinations(
s.Remove(s.IndexOf(c), 1),
length - 1
)
select c + combination;
}
Usage:
string s = "abcde";
var combinations = GetCombinations(s, 3);
Console.WriteLine(String.Join(", ", combinations));
Output:
abc, abd, abe, acb, acd, ace, adb, adc, ade, aeb, aec, aed, bac, bad, bae, bca,
bcd, bce, bda, bdc, bde, bea, bec, bed, cab, cad, cae, cba, cbd, cbe, cda, cdb,
cde, cea, ceb, ced, dab, dac, dae, dba, dbc, dbe, dca, dcb, dce, dea, deb, dec,
eab, eac, ead, eba, ebc, ebd, eca, ecb, ecd, eda, edb, edc

Here is my generic function which can return all the combinations of type T:
static IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetCombinations(list, length - 1)
.SelectMany(t => list, (t1, t2) => t1.Concat(new T[] { t2 }));
}
Usage:
Console.WriteLine(
string.Join(", ",
GetCombinations("abcde".ToCharArray(), 2).Select(list => string.Join("", list))
)
);
Output:
aa, ab, ac, ad, ae, ba, bb, bc, bd, be, ca, cb, cc, cd, ce, da, db, dc, dd, de, ea, eb, ec, ed, ee
UPDATED
Please see my answer here for other scenarios, e.g. permutations and k-combinations etc.

Combination of numbers in array by using arrays only and recursion:
static int n = 4;
int[] baseArr = { 1, 2, 3, 4 };
int[] LockNums;
static void Main(string[] args)
{
int len = baseArr.Length;
LockNums = new int[n];
for (int i = 0; i < n; i++)
{
int num = baseArr[i];
DoCombinations(num, baseArr, len);
//for more than 4 numbers the print screen is too long if we need to check the result next line will help
//Console.ReadLine();
}
}
private void DoCombinations(int lockNum, int[] arr, int arrLen )
{
int n1 = arr.Length;
// next line shows the difference in length between the previous and its previous array
int point = arrLen - n1;
LockNums[n - arr.Length] = lockNum;
int[] tempArr = new int[arr.Length - 1];
FillTempArr(lockNum, arr, tempArr);
//next condition will print the last number from the current combination
if (arr.Length == 1)
{
Console.Write(" {0}", lockNum);
Console.WriteLine();
}
for (int i = 0; i < tempArr.Length; i++)
{
if ((point == 1) && (i != 0))
{
//without this code the program will fail to print the leading number of the next combination
//and 'point' is the exact moment when this code has to be executed
PrintFirstNums(baseArr.Length - n1);
}
Console.Write(" {0}", lockNum);
int num1 = tempArr[i];
DoCombinations(num1, tempArr, n1);
}
}
private void PrintFirstNums(int missNums)
{
for (int i = 0; i < missNums; i++)
{
Console.Write(" {0}", LockNums[i]);
}
}
private void FillTempArr(int lockN, int[] arr, int[] tempArr)
{
int idx = 0;
foreach (int number in arr)
{
if (number != lockN)
{
tempArr[idx++] = number;
}
}
}
private void PrintResult(int[] arr)
{
foreach (int num in arr)
{
Console.Write(" {0}", num);
}
}

Related

How to find number of specific strings in a string in c#

There is a string: xxoxoxoxoxoxooxxxxox where x is a seat that is occupied and o is not, I have to find individual occupied seats, with both sides having an x.
I tried to look at
for (int i = 0; i < string.Length; i++) {
if(string[i]=='x' && string[i + 1]=='o' && string[i + 2] == 'x')
{
count++;
}
}
but i got error so I was wondering if theres a good way to do it.
As the question is pretty unclear, I am assuming that you are looking for a pattern xox and want to know the position of o.
you can run a for loop and get the index.
to get the count of such patterns. you can increment the count by 1.
string str = "xxoxoxoxoxoxooxxxxox";
for(int i = 0; i < str.Length - 2; i++)
{
if (str[i] == 'x' && str[i +1] == 'o' && str[i+ 2] == 'x')
{
Console.WriteLine(i + 1);
count++;
}
}
you can change the character value based on your requirement.
you can use regex.matches to find all matches ...
string s = "xxoxoxoxoxoxooxxxxox";
Regex rx = new Regex("xox");
foreach (Match match in rx.Matches(s))
{
Console.WriteLine("Match index: "+ match.Index);
}
RegEx approach which gives you all indices of individual occupied seats oxo https://dotnetfiddle.net/3jc1Vq
string input = "xxoxoxoxoxoxooxxxxox";
// ^ ^ ^ ^ ^ ^
int[] indices = Regex.Matches(input, "(?<=x)o(?=x)").Cast<Match>().Select(x => x.Index).ToArray();
// in case you only want the count
int count = Regex.Matches(input, "(?<=x)o(?=x)").Count();
I made a working example that makes use of ReadOnlySpan<T> and avoids RegEx and over allocation.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string seats = "xxoxoxoxoxoxooxxxxox";
var results = seats.ToCharArray().GetSingles('o');
foreach(var i in results)
{
Console.WriteLine(i);
}
}
}
public static class Ext
{
public static IReadOnlyList<int> GetSingles<T>(this T[] source, T search)
{
var results = new List<int>();
if(source.Length == 0)
{
return results;
}
if (source.Length == 1)
{
if (source[0].Equals(search))
{
results.Add(0);
}
return results;
}
if(source.Length >= 2)
{
if (source[0].Equals(search) && ! source[1].Equals(search))
{
results.Add(0);
}
if (source.Length == 2)
{
if (!source[0].Equals(search) && source[1].Equals(search))
{
results.Add(1);
}
return results;
}
}
ReadOnlySpan<T> window = new ReadOnlySpan<T>(source, 0, 3);
int i = 1;
for(; i < source.Length - 1; i++)
{
window = new ReadOnlySpan<T>(source, i - 1, 3);
if(!window[0].Equals(search) &&
window[1].Equals(search) &&
!window[2].Equals(search))
{
results.Add(i);
}
}
if(!window[1].Equals(search) && window[2].Equals(search))
{
results.Add(i + 1);
}
return results;
}
}
This outputs,
2
4
6
8
10
18
With the more challenging test data,
public class Program
{
public static void Main()
{
var tests = new string[]
{
"",
"o",
"x",
"oo",
"ox",
"xo",
"xx",
"oxx",
"oox",
"xox",
"xoo",
"xoxoxoxo",
"xoxoxoxoo",
"xoxoxox"
};
for(var i = 0; i < tests.Length; i++)
{
string seats = tests[i];
Console.WriteLine($"{i}:\"{seats}\"");
var results = seats.ToCharArray().GetSingles('o');
foreach(var r in results)
{
Console.WriteLine(r);
}
}
}
}
we get the correct output,
0:""
1:"o"
0
2:"x"
3:"oo"
4:"ox"
0
5:"xo"
1
6:"xx"
7:"oxx"
0
8:"oox"
9:"xox"
1
10:"xoo"
11:"xoxoxoxo"
1
3
5
8
12:"xoxoxoxoo"
1
3
5
13:"xoxoxox"
1
3
5

Index out of bounds of array but only sometimes [duplicate]

Suppose I had a string:
string str = "1111222233334444";
How can I break this string into chunks of some size?
e.g., breaking this into sizes of 4 would return strings:
"1111"
"2222"
"3333"
"4444"
static IEnumerable<string> Split(string str, int chunkSize)
{
return Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
}
Please note that additional code might be required to gracefully handle edge cases (null or empty input string, chunkSize == 0, input string length not divisible by chunkSize, etc.). The original question doesn't specify any requirements for these edge cases and in real life the requirements might vary so they are out of scope of this answer.
In a combination of dove+Konstatin's answers...
static IEnumerable<string> WholeChunks(string str, int chunkSize) {
for (int i = 0; i < str.Length; i += chunkSize)
yield return str.Substring(i, chunkSize);
}
This will work for all strings that can be split into a whole number of chunks, and will throw an exception otherwise.
If you want to support strings of any length you could use the following code:
static IEnumerable<string> ChunksUpto(string str, int maxChunkSize) {
for (int i = 0; i < str.Length; i += maxChunkSize)
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length-i));
}
However, the the OP explicitly stated he does not need this; it's somewhat longer and harder to read, slightly slower. In the spirit of KISS and YAGNI, I'd go with the first option: it's probably the most efficient implementation possible, and it's very short, readable, and, importantly, throws an exception for nonconforming input.
Why not loops? Here's something that would do it quite well:
string str = "111122223333444455";
int chunkSize = 4;
int stringLength = str.Length;
for (int i = 0; i < stringLength ; i += chunkSize)
{
if (i + chunkSize > stringLength) chunkSize = stringLength - i;
Console.WriteLine(str.Substring(i, chunkSize));
}
Console.ReadLine();
I don't know how you'd deal with case where the string is not factor of 4, but not saying you're idea is not possible, just wondering the motivation for it if a simple for loop does it very well? Obviously the above could be cleaned and even put in as an extension method.
Or as mentioned in comments, you know it's /4 then
str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize)
{Console.WriteLine(str.Substring(i, chunkSize));}
This is based on #dove solution but implemented as an extension method.
Benefits:
Extension method
Covers corner cases
Splits string with any chars: numbers, letters, other symbols
Code
public static class EnumerableEx
{
public static IEnumerable<string> SplitBy(this string str, int chunkLength)
{
if (String.IsNullOrEmpty(str)) throw new ArgumentException();
if (chunkLength < 1) throw new ArgumentException();
for (int i = 0; i < str.Length; i += chunkLength)
{
if (chunkLength + i > str.Length)
chunkLength = str.Length - i;
yield return str.Substring(i, chunkLength);
}
}
}
Usage
var result = "bobjoecat".SplitBy(3); // bob, joe, cat
Unit tests removed for brevity (see previous revision)
Using regular expressions and Linq:
List<string> groups = (from Match m in Regex.Matches(str, #"\d{4}")
select m.Value).ToList();
I find this to be more readable, but it's just a personal opinion. It can also be a one-liner : ).
How's this for a one-liner?
List<string> result = new List<string>(Regex.Split(target, #"(?<=\G.{4})", RegexOptions.Singleline));
With this regex it doesn't matter if the last chunk is less than four characters, because it only ever looks at the characters behind it.
I'm sure this isn't the most efficient solution, but I just had to toss it out there.
Starting with .NET 6, we can also use the Chunk method:
var result = str
.Chunk(4)
.Select(x => new string(x))
.ToList();
I recently had to write something that accomplishes this at work, so I thought I would post my solution to this problem. As an added bonus, the functionality of this solution provides a way to split the string in the opposite direction and it does correctly handle unicode characters as previously mentioned by Marvin Pinto above. So, here it is:
using System;
using Extensions;
namespace TestCSharp
{
class Program
{
static void Main(string[] args)
{
string asciiStr = "This is a string.";
string unicodeStr = "これは文字列です。";
string[] array1 = asciiStr.Split(4);
string[] array2 = asciiStr.Split(-4);
string[] array3 = asciiStr.Split(7);
string[] array4 = asciiStr.Split(-7);
string[] array5 = unicodeStr.Split(5);
string[] array6 = unicodeStr.Split(-5);
}
}
}
namespace Extensions
{
public static class StringExtensions
{
/// <summary>Returns a string array that contains the substrings in this string that are seperated a given fixed length.</summary>
/// <param name="s">This string object.</param>
/// <param name="length">Size of each substring.
/// <para>CASE: length > 0 , RESULT: String is split from left to right.</para>
/// <para>CASE: length == 0 , RESULT: String is returned as the only entry in the array.</para>
/// <para>CASE: length < 0 , RESULT: String is split from right to left.</para>
/// </param>
/// <returns>String array that has been split into substrings of equal length.</returns>
/// <example>
/// <code>
/// string s = "1234567890";
/// string[] a = s.Split(4); // a == { "1234", "5678", "90" }
/// </code>
/// </example>
public static string[] Split(this string s, int length)
{
System.Globalization.StringInfo str = new System.Globalization.StringInfo(s);
int lengthAbs = Math.Abs(length);
if (str == null || str.LengthInTextElements == 0 || lengthAbs == 0 || str.LengthInTextElements <= lengthAbs)
return new string[] { str.ToString() };
string[] array = new string[(str.LengthInTextElements % lengthAbs == 0 ? str.LengthInTextElements / lengthAbs: (str.LengthInTextElements / lengthAbs) + 1)];
if (length > 0)
for (int iStr = 0, iArray = 0; iStr < str.LengthInTextElements && iArray < array.Length; iStr += lengthAbs, iArray++)
array[iArray] = str.SubstringByTextElements(iStr, (str.LengthInTextElements - iStr < lengthAbs ? str.LengthInTextElements - iStr : lengthAbs));
else // if (length < 0)
for (int iStr = str.LengthInTextElements - 1, iArray = array.Length - 1; iStr >= 0 && iArray >= 0; iStr -= lengthAbs, iArray--)
array[iArray] = str.SubstringByTextElements((iStr - lengthAbs < 0 ? 0 : iStr - lengthAbs + 1), (iStr - lengthAbs < 0 ? iStr + 1 : lengthAbs));
return array;
}
}
}
Also, here is an image link to the results of running this code: http://i.imgur.com/16Iih.png
It's not pretty and it's not fast, but it works, it's a one-liner and it's LINQy:
List<string> a = text.Select((c, i) => new { Char = c, Index = i }).GroupBy(o => o.Index / 4).Select(g => new String(g.Select(o => o.Char).ToArray())).ToList();
This should be much faster and more efficient than using LINQ or other approaches used here.
public static IEnumerable<string> Splice(this string s, int spliceLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (spliceLength < 1)
throw new ArgumentOutOfRangeException("spliceLength");
if (s.Length == 0)
yield break;
var start = 0;
for (var end = spliceLength; end < s.Length; end += spliceLength)
{
yield return s.Substring(start, spliceLength);
start = end;
}
yield return s.Substring(start);
}
You can use morelinq by Jon Skeet. Use Batch like:
string str = "1111222233334444";
int chunkSize = 4;
var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray()));
This will return 4 chunks for the string "1111222233334444". If the string length is less than or equal to the chunk size Batch will return the string as the only element of IEnumerable<string>
For output:
foreach (var chunk in chunks)
{
Console.WriteLine(chunk);
}
and it will give:
1111
2222
3333
4444
Personally I prefer my solution :-)
It handles:
String lengths that are a multiple of the chunk size.
String lengths that are NOT a multiple of the chunk size.
String lengths that are smaller than the chunk size.
NULL and empty strings (throws an exception).
Chunk sizes smaller than 1 (throws an exception).
It is implemented as a extension method, and it calculates the number of chunks is going to generate beforehand. It checks the last chunk because in case the text length is not a multiple it needs to be shorter. Clean, short, easy to understand... and works!
public static string[] Split(this string value, int chunkSize)
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("The string cannot be null.");
if (chunkSize < 1) throw new ArgumentException("The chunk size should be equal or greater than one.");
int remainder;
int divResult = Math.DivRem(value.Length, chunkSize, out remainder);
int numberOfChunks = remainder > 0 ? divResult + 1 : divResult;
var result = new string[numberOfChunks];
int i = 0;
while (i < numberOfChunks - 1)
{
result[i] = value.Substring(i * chunkSize, chunkSize);
i++;
}
int lastChunkSize = remainder > 0 ? remainder : chunkSize;
result[i] = value.Substring(i * chunkSize, lastChunkSize);
return result;
}
Simple and short:
// this means match a space or not a space (anything) up to 4 characters
var lines = Regex.Matches(str, #"[\s\S]{0,4}").Cast<Match>().Select(x => x.Value);
I know question is years old, but here is a Rx implementation. It handles the length % chunkSize != 0 problem out of the box:
public static IEnumerable<string> Chunkify(this string input, int size)
{
if(size < 1)
throw new ArgumentException("size must be greater than 0");
return input.ToCharArray()
.ToObservable()
.Buffer(size)
.Select(x => new string(x.ToArray()))
.ToEnumerable();
}
public static IEnumerable<IEnumerable<T>> SplitEvery<T>(this IEnumerable<T> values, int n)
{
var ls = values.Take(n);
var rs = values.Skip(n);
return ls.Any() ?
Cons(ls, SplitEvery(rs, n)) :
Enumerable.Empty<IEnumerable<T>>();
}
public static IEnumerable<T> Cons<T>(T x, IEnumerable<T> xs)
{
yield return x;
foreach (var xi in xs)
yield return xi;
}
Best , Easiest and Generic Answer :).
string originalString = "1111222233334444";
List<string> test = new List<string>();
int chunkSize = 4; // change 4 with the size of strings you want.
for (int i = 0; i < originalString.Length; i = i + chunkSize)
{
if (originalString.Length - i >= chunkSize)
test.Add(originalString.Substring(i, chunkSize));
else
test.Add(originalString.Substring(i,((originalString.Length - i))));
}
static IEnumerable<string> Split(string str, int chunkSize)
{
IEnumerable<string> retVal = Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize))
if (str.Length % chunkSize > 0)
retVal = retVal.Append(str.Substring(str.Length / chunkSize * chunkSize, str.Length % chunkSize));
return retVal;
}
It correctly handles input string length not divisible by chunkSize.
Please note that additional code might be required to gracefully handle edge cases (null or empty input string, chunkSize == 0).
static IEnumerable<string> Split(string str, double chunkSize)
{
return Enumerable.Range(0, (int) Math.Ceiling(str.Length/chunkSize))
.Select(i => new string(str
.Skip(i * (int)chunkSize)
.Take((int)chunkSize)
.ToArray()));
}
and another approach:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var x = "Hello World";
foreach(var i in x.ChunkString(2)) Console.WriteLine(i);
}
}
public static class Ext{
public static IEnumerable<string> ChunkString(this string val, int chunkSize){
return val.Select((x,i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/chunkSize, x => x.Value)
.Select(x => string.Join("",x));
}
}
Six years later o_O
Just because
public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront)
{
var count = (int) Math.Ceiling(str.Length/(double) chunkSize);
Func<int, int> start = index => remainingInFront ? str.Length - (count - index)*chunkSize : index*chunkSize;
Func<int, int> end = index => Math.Min(str.Length - Math.Max(start(index), 0), Math.Min(start(index) + chunkSize - Math.Max(start(index), 0), chunkSize));
return Enumerable.Range(0, count).Select(i => str.Substring(Math.Max(start(i), 0),end(i)));
}
or
private static Func<bool, int, int, int, int, int> start = (remainingInFront, length, count, index, size) =>
remainingInFront ? length - (count - index) * size : index * size;
private static Func<bool, int, int, int, int, int, int> end = (remainingInFront, length, count, index, size, start) =>
Math.Min(length - Math.Max(start, 0), Math.Min(start + size - Math.Max(start, 0), size));
public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront)
{
var count = (int)Math.Ceiling(str.Length / (double)chunkSize);
return Enumerable.Range(0, count).Select(i => str.Substring(
Math.Max(start(remainingInFront, str.Length, count, i, chunkSize), 0),
end(remainingInFront, str.Length, count, i, chunkSize, start(remainingInFront, str.Length, count, i, chunkSize))
));
}
AFAIK all edge cases are handled.
Console.WriteLine(string.Join(" ", "abc".Split(2, false))); // ab c
Console.WriteLine(string.Join(" ", "abc".Split(2, true))); // a bc
Console.WriteLine(string.Join(" ", "a".Split(2, true))); // a
Console.WriteLine(string.Join(" ", "a".Split(2, false))); // a
List<string> SplitString(int chunk, string input)
{
List<string> list = new List<string>();
int cycles = input.Length / chunk;
if (input.Length % chunk != 0)
cycles++;
for (int i = 0; i < cycles; i++)
{
try
{
list.Add(input.Substring(i * chunk, chunk));
}
catch
{
list.Add(input.Substring(i * chunk));
}
}
return list;
}
I took this to another level. Chucking is an easy one liner, but in my case I needed whole words as well. Figured I would post it, just in case someone else needs something similar.
static IEnumerable<string> Split(string orgString, int chunkSize, bool wholeWords = true)
{
if (wholeWords)
{
List<string> result = new List<string>();
StringBuilder sb = new StringBuilder();
if (orgString.Length > chunkSize)
{
string[] newSplit = orgString.Split(' ');
foreach (string str in newSplit)
{
if (sb.Length != 0)
sb.Append(" ");
if (sb.Length + str.Length > chunkSize)
{
result.Add(sb.ToString());
sb.Clear();
}
sb.Append(str);
}
result.Add(sb.ToString());
}
else
result.Add(orgString);
return result;
}
else
return new List<string>(Regex.Split(orgString, #"(?<=\G.{" + chunkSize + "})", RegexOptions.Singleline));
}
Results based on below comment:
string msg = "336699AABBCCDDEEFF";
foreach (string newMsg in Split(msg, 2, false))
{
Console.WriteLine($">>{newMsg}<<");
}
Console.ReadKey();
Results:
>>33<<
>>66<<
>>99<<
>>AA<<
>>BB<<
>>CC<<
>>DD<<
>>EE<<
>>FF<<
>><<
Another way to pull it:
List<string> splitData = (List<string>)Split(msg, 2, false);
for (int i = 0; i < splitData.Count - 1; i++)
{
Console.WriteLine($">>{splitData[i]}<<");
}
Console.ReadKey();
New Results:
>>33<<
>>66<<
>>99<<
>>AA<<
>>BB<<
>>CC<<
>>DD<<
>>EE<<
>>FF<<
An important tip if the string that is being chunked needs to support all Unicode characters.
If the string is to support international characters like 𠀋, then split up the string using the System.Globalization.StringInfo class. Using StringInfo, you can split up the string based on number of text elements.
string internationalString = '𠀋';
The above string has a Length of 2, because the String.Length property returns the number of Char objects in this instance, not the number of Unicode characters.
Changed slightly to return parts whose size not equal to chunkSize
public static IEnumerable<string> Split(this string str, int chunkSize)
{
var splits = new List<string>();
if (str.Length < chunkSize) { chunkSize = str.Length; }
splits.AddRange(Enumerable.Range(0, str.Length / chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize)));
splits.Add(str.Length % chunkSize > 0 ? str.Substring((str.Length / chunkSize) * chunkSize, str.Length - ((str.Length / chunkSize) * chunkSize)) : string.Empty);
return (IEnumerable<string>)splits;
}
I think this is an straight forward answer:
public static IEnumerable<string> Split(this string str, int chunkSize)
{
if(string.IsNullOrEmpty(str) || chunkSize<1)
throw new ArgumentException("String can not be null or empty and chunk size should be greater than zero.");
var chunkCount = str.Length / chunkSize + (str.Length % chunkSize != 0 ? 1 : 0);
for (var i = 0; i < chunkCount; i++)
{
var startIndex = i * chunkSize;
if (startIndex + chunkSize >= str.Length)
yield return str.Substring(startIndex);
else
yield return str.Substring(startIndex, chunkSize);
}
}
And it covers edge cases.
static List<string> GetChunks(string value, int chunkLength)
{
var res = new List<string>();
int count = (value.Length / chunkLength) + (value.Length % chunkLength > 0 ? 1 : 0);
Enumerable.Range(0, count).ToList().ForEach(f => res.Add(value.Skip(f * chunkLength).Take(chunkLength).Select(z => z.ToString()).Aggregate((a,b) => a+b)));
return res;
}
demo
Here's my 2 cents:
IEnumerable<string> Split(string str, int chunkSize)
{
while (!string.IsNullOrWhiteSpace(str))
{
var chunk = str.Take(chunkSize).ToArray();
str = str.Substring(chunk.Length);
yield return new string(chunk);
}
}//Split
I've slightly build up on João's solution.
What I've done differently is in my method you can actually specify whether you want to return the array with remaining characters or whether you want to truncate them if the end characters do not match your required chunk length, I think it's pretty flexible and the code is fairly straight forward:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace SplitFunction
{
class Program
{
static void Main(string[] args)
{
string text = "hello, how are you doing today?";
string[] chunks = SplitIntoChunks(text, 3,false);
if (chunks != null)
{
chunks.ToList().ForEach(e => Console.WriteLine(e));
}
Console.ReadKey();
}
private static string[] SplitIntoChunks(string text, int chunkSize, bool truncateRemaining)
{
string chunk = chunkSize.ToString();
string pattern = truncateRemaining ? ".{" + chunk + "}" : ".{1," + chunk + "}";
string[] chunks = null;
if (chunkSize > 0 && !String.IsNullOrEmpty(text))
chunks = (from Match m in Regex.Matches(text,pattern)select m.Value).ToArray();
return chunks;
}
}
}
public static List<string> SplitByMaxLength(this string str)
{
List<string> splitString = new List<string>();
for (int index = 0; index < str.Length; index += MaxLength)
{
splitString.Add(str.Substring(index, Math.Min(MaxLength, str.Length - index)));
}
return splitString;
}
I can't remember who gave me this, but it works great. I speed tested a number of ways to break Enumerable types into groups. The usage would just be like this...
List<string> Divided = Source3.Chunk(24).Select(Piece => string.Concat<char>(Piece)).ToList();
The extention code would look like this...
#region Chunk Logic
private class ChunkedEnumerable<T> : IEnumerable<T>
{
class ChildEnumerator : IEnumerator<T>
{
ChunkedEnumerable<T> parent;
int position;
bool done = false;
T current;
public ChildEnumerator(ChunkedEnumerable<T> parent)
{
this.parent = parent;
position = -1;
parent.wrapper.AddRef();
}
public T Current
{
get
{
if (position == -1 || done)
{
throw new InvalidOperationException();
}
return current;
}
}
public void Dispose()
{
if (!done)
{
done = true;
parent.wrapper.RemoveRef();
}
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
position++;
if (position + 1 > parent.chunkSize)
{
done = true;
}
if (!done)
{
done = !parent.wrapper.Get(position + parent.start, out current);
}
return !done;
}
public void Reset()
{
// per http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx
throw new NotSupportedException();
}
}
EnumeratorWrapper<T> wrapper;
int chunkSize;
int start;
public ChunkedEnumerable(EnumeratorWrapper<T> wrapper, int chunkSize, int start)
{
this.wrapper = wrapper;
this.chunkSize = chunkSize;
this.start = start;
}
public IEnumerator<T> GetEnumerator()
{
return new ChildEnumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
private class EnumeratorWrapper<T>
{
public EnumeratorWrapper(IEnumerable<T> source)
{
SourceEumerable = source;
}
IEnumerable<T> SourceEumerable { get; set; }
Enumeration currentEnumeration;
class Enumeration
{
public IEnumerator<T> Source { get; set; }
public int Position { get; set; }
public bool AtEnd { get; set; }
}
public bool Get(int pos, out T item)
{
if (currentEnumeration != null && currentEnumeration.Position > pos)
{
currentEnumeration.Source.Dispose();
currentEnumeration = null;
}
if (currentEnumeration == null)
{
currentEnumeration = new Enumeration { Position = -1, Source = SourceEumerable.GetEnumerator(), AtEnd = false };
}
item = default(T);
if (currentEnumeration.AtEnd)
{
return false;
}
while (currentEnumeration.Position < pos)
{
currentEnumeration.AtEnd = !currentEnumeration.Source.MoveNext();
currentEnumeration.Position++;
if (currentEnumeration.AtEnd)
{
return false;
}
}
item = currentEnumeration.Source.Current;
return true;
}
int refs = 0;
// needed for dispose semantics
public void AddRef()
{
refs++;
}
public void RemoveRef()
{
refs--;
if (refs == 0 && currentEnumeration != null)
{
var copy = currentEnumeration;
currentEnumeration = null;
copy.Source.Dispose();
}
}
}
/// <summary>Speed Checked. Works Great!</summary>
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
if (chunksize < 1) throw new InvalidOperationException();
var wrapper = new EnumeratorWrapper<T>(source);
int currentPos = 0;
T ignore;
try
{
wrapper.AddRef();
while (wrapper.Get(currentPos, out ignore))
{
yield return new ChunkedEnumerable<T>(wrapper, chunksize, currentPos);
currentPos += chunksize;
}
}
finally
{
wrapper.RemoveRef();
}
}
#endregion
class StringHelper
{
static void Main(string[] args)
{
string str = "Hi my name is vikas bansal and my email id is bansal.vks#gmail.com";
int offSet = 10;
List<string> chunks = chunkMyStr(str, offSet);
Console.Read();
}
static List<string> chunkMyStr(string str, int offSet)
{
List<string> resultChunks = new List<string>();
for (int i = 0; i < str.Length; i += offSet)
{
string temp = str.Substring(i, (str.Length - i) > offSet ? offSet : (str.Length - i));
Console.WriteLine(temp);
resultChunks.Add(temp);
}
return resultChunks;
}
}

How to add array values to equal a number, or fail if values in array wont work

I am trying to build a calculator that will tell me what "steps" are needed to stack up to a given value. Using only that "steps" available in the array.
Example:
decimal[] blocks {.05, .100, .150, .200, .250}
goal = .550m
result = .100, .200, .250
I have tried using nested if statements and array find/last with not much luck.
I can get a match if the goal is an exact match, or will match with two of them stacked. I can't get it to work for the max(.750).
This is what I have so far:
code:
string result = "nope";
decimal goal = 3.264m;
decimal[] DAStep = new decimal[10];
decimal temp = Array.Find(GaugeBlockArray, element => element.Equals(goal));
if (temp != 0m)
{
DAStep[0] = Array.Find(GaugeBlockArray, element => element.Equals(temp));
result = DAStep[0].ToString();
}
else
{
DAStep[0] = GaugeBlockArray.Last(element => element <= goal); ;
decimal remaining;
remaining = goal - DAStep[0];
while (remaining != 0m)
{
DAStep[1] = GaugeBlockArray.Last(element => element <= remaining);
if (DAStep[1] != remaining)
{
DAStep[2] = GaugeBlockArray.Last(element => element <= (DAStep[1] - .0001m));
if (DAStep[2] == 0) { DAStep[1] = DAStep[2]; }
}
}
}
GaugeBlockArray contains an array of 72 different elements from .05 to 4.0. And, I can only use each block once.
edit:
I guess more detail on the array contents may help getting to a solution.
GaugeBlockArray:
.05
.100
.1001
.1002
.1003
.1004
.1005
.1006
.1007
.1008
.1009
.110
.111
.112
.113
.114
.115
.116
.117
.118
.119
.120
.121
.122
.123
.124
.125
.126
.127
.128
.129
.130
.131
.132
.133
.134
.135
.136
.137
.138
.139
.140
.141
.142
.143
.144
.145
.146
.147
.148
.149
.150
.200
.250
.300
.350
.400
.450
.500
.550
.600
.650
.700
.750
.800
.850
.900
.950
1.000
2.000
3.000
4.000
Many thanks to #GeorgPatscheider for getting me pointed in the right direction!
This is my final working result:
public static void CountSum(decimal[] DNumbers, decimal Dsum)
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MetTracker.GaugeCalc))
{
(window as MetTracker.GaugeCalc).CalculateBtn.Content = "working...";
}
}
DNumbers = Array.ConvertAll(DNumbers, element => 10000m * element);
string TempString = GetSettingsStrings("GBCMaxStep"); // only used to initialize max step value
Dsum = Dsum * 10000m;
Int32 Isum = Convert.ToInt32(Dsum);
Int32[] INumbers = Array.ConvertAll(DNumbers, element => (Int32)element);
// int result = 0;
GetmNumberOfSubsets(INumbers, Isum);
success = false;
return;
}
private static void GetmNumberOfSubsets(Int32[] numbers, Int32 Isum)
{
set = numbers;
sum = Isum;
FindSubsetSum();
}
//-------------------------------------------------------------
static Int32[] set;
static Int32[] subSetIndexes;
static Int32 sum;
static Int32 numberOfSubsetSums;
static bool success = false;
static List<Int32> ResultSet = new List<Int32>();
static List<string> results = new List<string>();//------------------------------------------------------------
/*
Method: FindSubsetSum()
*/
private static void FindSubsetSum()
{
numberOfSubsetSums = 0;
Int32 numberOfElements = set.Length;
FindPowerSet(numberOfElements);
}
//-------------------------------------------------------------
/*
Method: FindPowerSet(int n, int k)
*/
private static void FindPowerSet(Int32 n)
{
// Super set - all sets with size: 0, 1, ..., n - 1
for (Int32 k = 0; k <= n - 1; k++)
{
subSetIndexes = new Int32[k];
CombinationsNoRepetition(k, 0, n - 1);
if(subSetIndexes.Length >= GBC_MaxStepSetting) {
break; }
}
if (numberOfSubsetSums == 0)
{
MessageBox.Show("No subsets with wanted sum exist.");
}
}
//-------------------------------------------------------------
/*
Method: CombinationsNoRepetition(int k, int iBegin, int iEnd);
*/
private static void CombinationsNoRepetition(Int32 k, Int32 iBegin, Int32 iEnd)
{
if (k == 0)
{
PrintSubSet();
return;
}
if (success == false)
{
for (Int32 i = iBegin; i <= iEnd; i++)
{
subSetIndexes[k - 1] = i;
++iBegin;
CombinationsNoRepetition(k - 1, iBegin, iEnd);
if (success == true)
break;
}
}
return;
}
private static void PrintSubSet()
{
Int32 currentSubsetSum = 0;
// accumulate sum of current subset
for (Int32 i = 0; i < subSetIndexes.Length; i++)
{
currentSubsetSum += set[subSetIndexes[i]];
if(currentSubsetSum > sum) { break; }
}
if(currentSubsetSum > sum) { return; }
// if wanted sum: print current subset elements
if (currentSubsetSum == sum)
{
++numberOfSubsetSums;
// results.Add("(");
for (Int32 i = 0; i < subSetIndexes.Length; i++)
{
results.Add((set[subSetIndexes[i]]).ToString());
ResultSet.Add(set[subSetIndexes[i]]);
if (i < subSetIndexes.Length - 1)
{
// results.Add(" ,");
}
}
// results.Add(")");
Int32[] ResultSetArr = ResultSet.ToArray();
decimal[] ResultSetArrD = Array.ConvertAll(ResultSetArr, element => (decimal)element);
ResultSetArrD = Array.ConvertAll(ResultSetArrD, element => element / 10000m);
// var message = string.Join(Environment.NewLine, ResultSetArrD);
// message = string.Format("{0:0.0000}", message);
int l = ResultSetArrD.Length;
string[] ResultString = new string[l];
foreach(int i in ResultSetArrD)
{ResultString = Array.ConvertAll(ResultSetArrD, element => element.ToString("0.0000"));}
var message = string.Join(Environment.NewLine, ResultString);
decimal ResultSum = ResultSetArrD.Sum();
MessageBox.Show(message + "\n= " + ResultSum.ToString("0.0000"), "Result");
Array.Clear(ResultSetArrD, 0, ResultSetArrD.Length);
Array.Clear(ResultSetArr, 0, ResultSetArr.Length);
ResultSet.Clear();
message = null;
success = true;
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MetTracker.GaugeCalc))
{
(window as MetTracker.GaugeCalc).CalculateBtn.Content = "Calculate";
}
}
return;
}
if (success == true)
return;
}
I added some limiting to reduce the amount of time before it reports a failure to find a combo. I also convert the array to a double to get around the headache the decimals were causing me. Works great!

How can I reduce the complexity of these two methods?

I have some code like
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
// returns true or false based on whether s1 and s2 are
// an unordered anagrammatic pair
// e.g. "aac","cac" --> false
// "aac","aca" --> true
// Complexity: O(n)
static bool IsAnagrammaticPair(string s1, string s2)
{
if(s1.Length != s2.Length)
return false;
int[] counter1 = new int[26],
counter2 = new int[26];
for(int i = 0; i < s1.Length; ++i)
{
counter1[(int)s1[i] - (int)'a'] += 1;
counter2[(int)s2[i] - (int)'a'] += 1;
}
for(int i = 0; i < 26; ++i)
if(counter1[i] != counter2[i])
return false;
return true;
}
// gets all substrings of s (not including the empty string,
// including s itself)
// Complexity: O(n^2)
static IEnumerable<string> GetSubstrings(string s)
{
return from i in Enumerable.Range(0, s.Length)
from j in Enumerable.Range(0, s.Length - i + 1)
where j >= 1
select s.Substring(i, j);
}
// gets the number of anagrammatical pairs of substrings in s
// Complexity: O(n^2)
static int NumAnagrammaticalPairs(string s)
{
var substrings = GetSubstrings(s).ToList();
var indices = Enumerable.Range(0, substrings.Count);
return (from i in indices
from j in indices
where i < j && IsAnagrammaticPair(substrings[i], substrings[j])
select 1).Count();
}
static void Main(String[] args)
{
int T = Int32.Parse(Console.ReadLine());
for(int t = 0; t < T; ++t)
{
string line = Console.ReadLine();
Console.WriteLine(NumAnagrammaticalPairs(line));
}
}
}
which is not meeting the performance benchmarks of the problem. The two helper methods I have
GetSubstrings
and
NumAnagrammaticalPairs
I know are O(n^2) as I mentioned in the comments, however I don't see how I can reduce the number of operations involved in retrieving the answer. Any ideas?
You can use LINQ to check for anagarmatic pair. Not sure about performance though.
public class Program
{
public static void Main()
{
string x="aac";
string y ="caa";
List<char> lstX = x.ToCharArray().OrderBy(m=>m).ToList<char>();
List<char> lstY =y.ToCharArray().OrderBy(m=>m).ToList<char>();
Console.WriteLine(IsAnagramaticPair(x,y));
}
public static bool IsAnagramaticPair(string x ,string y)
{
List<char> lstX = x.ToCharArray().OrderBy(m=>m).ToList<char>();
List<char> lstY =y.ToCharArray().OrderBy(m=>m).ToList<char>();
return lstX.SequenceEqual(lstY);
}
}
There are two possibilities that come to mind. First, sort both strings and compare the results:
static bool IsAnagrammaticPair(string s1, string s2)
{
var srt1 = s1.OrderBy(c => c);
var srt2 = s2.OrderBy(c => c);
return s1.SequenceEqual(s2);
}
If m and n are the lengths of the strings, then that is O(n log n + m log m).
Another possibility is to make a histogram of characters from one string, and then compare the characters and associated counts from the other string. The strings have to be the same length for that to work, though:
static bool IsAnagrammaticPair(string s1, string s2)
{
if (s1.Length != s2.Length) return false;
var l1 = s1.ToLookup(c => c);
return s2.GroupBy(c => c).All(g => l1.Contains(g.Key) && l1[g.Key].Count() == g.Count());
}
That's O(n) for the first part, with O(n) extra space. And O(m) for the second part.
You can take subsets of the substrings so that each subset is composed of strings having the same length.
After that you can or using a sort O(n log n) to make a direct comparison between the strings.
And also use the sort to arrange each subset in the good order (so no ixj comparisons).
static void Main( string[] args )
{
int T = Int32.Parse( Console.ReadLine() );
for ( int t = 0 ; t < T ; ++t )
{
string line = Console.ReadLine();
Console.WriteLine( NumAnagrammaticalPairs( line ) );
}
}
static int NumAnagrammaticalPairs( string s )
{
int sum = 0;
foreach ( var substrings in GetSubstringsByLength( s ) )
{
// Count for each string how many others are identical
int toSum = 0;
for ( int i = 1 ; i < substrings.Count ; i++ )
if ( substrings[i - 1] == substrings[i] )
{
toSum++;
sum += toSum;
}
else
{
toSum = 0;
}
}
return sum;
}
static IEnumerable<List<string>> GetSubstringsByLength( string s )
{
for ( int length = 1 ; length < s.Length ; length++ )
yield return GetSubstringsOfLength( s, length );
}
static List<string> GetSubstringsOfLength( string s, int length )
{
var result = new List<string>();
for ( int i = 0 ; i <= s.Length - length ; i++ )
{
var substring = s.Substring( i, length );
result.Add( new string( substring.OrderBy( c => c ).ToArray<char>() ) );
}
result.Sort();
return result;
}

End of method reached but compiler jumps back in

just for fun I am trying to do the change making problem - more or less. My problem is that I get doubled results and through using the debugger I found out that the compiler jumps back into the method again even when it should finish.
private static void Main(string[] args)
{
string temp = Console.ReadLine();
int input;
if (int.TryParse(temp, out input))
{
if(input == 0)
{
System.Environment.Exit(Environment.ExitCode);
}
else
{
ChangeMaking(input);
}
}
else
{
Console.WriteLine("Not a number.");
}
}
private static int ChangeMakingHelper(int input, int euro)
{
return input / euro;
}
static int[] euro = { 1, 2, 5, 10, 20, 50, 100, 200, 500 };
static int counter = 0;
static List<int[]> result = new List<int[]>();
static int[] tempResult = new int[euro.Length];
private static void ChangeMaking(int input)
{
for (int i = euro.Length -1; i >= 0; i--)
{
if(euro[i] <= input)
{
tempResult[i] = ChangeMakingHelper(input, euro[i]);
input = input - euro[i];
if((input % euro[i] != 0))
{
ChangeMaking(input % euro[i]);
}
}
}
result.Add(tempResult);
}
For example if the input is 11 then after the for-loop completes and adding tempResult to result the compiler jumps back into this part:
if((input % euro[i] != 0))
{
ChangeMaking(input % euro[i]);
}
My expected behavior for input 11 would be one array with this values {1, 0, 0, 1, 0, 0, 0, 0, 0} which I get but doubled.
The issue is that you are using static variables to pass data between function calls. Don't do that. Use return values instead.
public static void Main()
{
var result = ChangeMaking(11);
Console.WriteLine(string.Join(", ", result));
}
private static int ChangeMakingHelper(int input, int euro)
{
return input / euro;
}
static readonly int[] euro = { 1, 2, 5, 10, 20, 50, 100, 200, 500 };
private static int[] ChangeMaking(int input)
{
var result = new int[euro.Length];
for (int i = euro.Length -1; i >= 0; i--)
{
if (euro[i] <= input)
{
result[i] += ChangeMakingHelper(input, euro[i]);
input = input - euro[i];
if (input % euro[i] != 0)
{
var tempResult = ChangeMaking(input % euro[i]);
// Transfer the results to the local result array
for(int j = 0; j < result.Length; j++)
result[j] += tempResult[j];
}
// Also add a break statement here so you don't add the lower values twice!
break;
}
}
return result;
}
Fiddle: https://dotnetfiddle.net/7WnLWN
By the way, the reason you ended up with 2 arrays in your output is because you called ChangeMaking recursively, so it got called twice, so it called result.Add(tempResult) twice. Getting rid of the static variables as I have shown above fixes that.
Also, there's probably a more efficient way to do this without recursion, but that would require restructuring your algorithm a bit, so I'll leave that to you to figure out :)

Categories