split a string array to a jagged object array - c#

I want to make a string array with values of names and some numbers(which are strings)
i want to pass them into a function that will take the array and then split them into an object jagged array (1 array of strings and 1 array of ints)
the array is:
string[] str= { "toto", "the", "moto", "my", "friend","12","13","14","99","88"};
and the function looks like this:
public object[][] bloop (string[] bstr)
{
}
whats next?

Your scenario looks like bad design that can cause errors and performance issues. The better way is to change code for using generic List<> or something like that. But in your current problem you can use below code:
public object[][] bloop (string[] bstr)
{
var numbers = new List<int>();
var strings = new List<string>();
var result = new object[2][];
foreach(var str in bstr)
{
int number = 0;
if(int.TryParse(str, out number))
{
numbers.Add(number);
}
else
{
strings.Add(str);
}
}
result[0] = strings.ToArray();
result[1] = numbers.ToArray();
return result;
}

public static object[][] bloop(string[] bstr)
{
object[][] result = new object[2][] { new object[bstr.Length], new object[bstr.Length] };
int sFlag = 0, iFlag = 0, val;
foreach (string str in bstr)
if (int.TryParse(str, out val))
result[1][iFlag++] = val;
else
result[0][sFlag++] = str;
return result;
}

I agree that your requirement sounds odd and should be solved with a different approach. However, this will do what you want:
public T[][] Bloop<T>(T[] items)
{
if (items == null) throw new ArgumentNullException("items");
if (items.Length == 1) return new T[][] { items, new T[] { } };
int firstLength = (int) Math.Ceiling((double)items.Length / 2);
T[] firstPart = new T[firstLength];
Array.Copy(items, 0, firstPart, 0, firstLength);
int secondLength = (int)Math.Floor((double)items.Length / 2);
T[] secondPart = new T[secondLength];
Array.Copy(items, firstLength, secondPart, 0, secondLength);
return new T[][] { firstPart, secondPart };
}
Your sample:
string[] str= { "toto", "the", "moto", "my", "friend","12","13","14","99","88"};
string[][] result = Bloop(str);
If you need the second array as int[] you could use following:
int[] ints = Array.ConvertAll(result[1], int.Parse);

Linq solution.
You have two groups: first one has items that can be parsed to int and the second group contains all the others, so GroupBy looks quite naturally:
public Object[][] bloop(string[] bstr) {
if (null == bstr)
throw new ArgumentNullException("bstr");
int v;
return bstr
.GroupBy(x => int.TryParse(x, out v))
.OrderBy(chunk => chunk.Key) // let strings be the first
.Select(chunk => chunk.ToArray())
.ToArray();
}
Test:
string[] str = { "toto", "the", "moto", "my", "friend", "12", "13", "14", "99", "88" };
// toto, the, moto, my, friend
// 12, 13, 14, 99, 88
Console.Write(String.Join(Environment.NewLine,
bloop(str).Select(x => String.Join(", ", x))));

Related

Group array of string arrays with LINQ

I have array like this, values are string:
var arr1 = new [] { "H", "item1", "item2" };
var arr2 = new [] { "T", "thing1", "thing2" };
var arr3 = new [] { "T", "thing1", "thing2" };
var arr4 = new [] { "END", "something" };
var arr5 = new [] { "H", "item1", "item2" };
var arr6 = new [] { "T", "thing1", "thing2" };
var arr7 = new [] { "T", "thing1", "thing2" };
var arr8 = new [] { "END", "something" };
var allArrays = new [] { arr1, arr2, arr3, arr4, arr5, arr6, arr7, arr8 };
I need to group this in to a new array of arrays, so that one array has arrays that start with H or T. The END records (not included in the results) are the delimiters between each section; each new array starts after an END array.
In the end I would like to have somethng like this:
[
[ [H, item1, item2], [T, thing1, thing2], [T, thing1, thing2] ]
[ [H, item1, item2], [T, thing1, thing2], [T, thing1, thing2] ]
]
I know how I can do this with for each loop, but I'm looking for a cleaner way, possibly using linq. All suggestions are much valued, thank you!
you can try this
List<string[]> list = new List<string[]>();
var newArr = allArrays.Select(a => AddToArr(list, a)).Where(a => a != null);
and helper (this code can be put inline, but it easier to read this way)
private static string[][] AddToArr(List<string[]> list, string[] arr)
{
if (arr[0] != "END")
{
list.Add(arr);
return null;
}
var r = list.ToArray();
list.Clear();
return r;
}
result
[
[["H","item1","item2"],["T","thing1","thing2"],["T","thing1","thing2"]],
[["H","item3","item4"],["T","thing3","thing4"],["T","thing5","thing6"]]
]
So arr1, arr2, etc are string[].
allArrays is a string[][].
I hope you gave a meaningful example. From this example it seems that you want all string[] from allArrays, except the string[] that have a [0] that equals the word "END".
If this is what you want, your result is:
string[][] result = allArrays.Where(stringArray => stringArray[0] != "END");
I need to group this in to a new array of arrays, so that one array has arrays that start with H or T. The END records (not included in the results) are the delimiters between each section; each new array starts after an END array.
This is not exactly the same as I see in your example: what if one of the string arrays in allArrays is an empty array, or if it has the value null values. What if one of the the arrays of strings is empty (= length 0), and what if one of the string arrays doesn't start with "H", nor "T", nor "END"?
Literally you say that you only want the string arrays that start with "H" or "T", no other ones. You don't want string arrays that are null, nor empty string arrays. You also don't want string arrays that start with "END", nor the ones that start with String.Empty, or "A" or "B" or anything else than "H" or "T".
If I take your requirement literally, your code should be:
string[] requiredStringAtIndex0 = new string[] {"H", "T"};
string[][] result = allArrays.Where(stringArray => stringArray != null
&& stringArray.Length != 0
&& requiredStringAtIndex0.Contains(stringArray[0]));
In words: from allArrays, keep only those arrays of strings, that are not null, AND that have at least one element AND where the element at index 0 contains either "H" or "T"
Normally I would use an extension method for grouping runs of items based on a predicate, in this case GroupByEndingWith and then throw away the "END" record, like so:
var ans = allArrays.GroupByEndingWith(r => r[0] == "END")
.Select(g => g.Drop(1).ToArray())
.ToArray();
But, in general, you can use Aggregate to collect items based on a predicate at the expense of comprehension. It often helps to use a tuple to track an overall accumulator and a sub-accumulator. Unfortunately, there is no + operator or Append for List<T> that returns the original list (helpful for expression based accumulation) and since C# doesn't yet have a comma operator equivalent, you need an extension method again or you can use ImmutableList.
Using Aggregate and ImmutableList, you can do:
var ans = allArrays.Aggregate(
(ans: ImmutableList<ImmutableList<string[]>>.Empty, curr: ImmutableList<string[]>.Empty),
(ac, r) => r[0] == "END"
? (ac.ans.Add(ac.curr), ImmutableList<string[]>.Empty)
: (ac.ans, ac.curr.Add(r))
).ans
.Select(l => l.ToArray())
.ToArray();
NOTE: You can also do this with List if you are willing to create new Lists a lot:
var ans = allArrays.Aggregate(
(ans: new List<List<string[]>>(), curr: new List<string[]>()),
(ac, r) => r[0] == "END"
? (ac.ans.Concat(new[] { ac.curr }).ToList(), new List<string[]>())
: (ac.ans, ac.curr.Concat(new[] { r }).ToList())
).ans
.Select(l => l.ToArray())
.ToArray();
Here is a simple implementation.
public static void Main(string[] args)
{
var data = ConvertToArrayOfArray(arr1, arr2, arr3, arrr4, arr5, arr6, arr7, arr8);
}
private string[][] ConvertToArrayOfArray(params string[][] arrs)
{
List<string[]> yoList = new List<string[]>();
arrs.ToList().ForEach(x =>
{
if(!x[0] == "END") yoList.Add(x);
});
return yoList.ToArray();
}

Extract Number from string arrays

I have a string array and those includes different types of strings and I would like to separate those values in 2 different arrays.
string[] arr = { "12" , "34-2-2" , "xyz" , "33" , "56-3-4" , "45-4" }
Now I want linq query which gives me "12" , "33" in one and "34-2-2" , "56-3-4" in other array. Rest of the values will be ignored.
var _cust= DbContext.Customer.AsQueryable();
This will contain Id (Int32) and in this I want to add query which return if the customer has "12" , "33" will return that result.
var _cont = DbContext.Contacts.AsQueryable();
This will contain DisplayId (string) and in this I want to add query which return if the customer has "34-2-2" , "56-3-4" will return that result.
How can I write linq query for this?
You can use linq with regex pretty simply to solve this...
string[] arr = {"12", "34-2-2", "xyz", "33", "56-3-4", "45-4"};
var first = arr.Where(v => Regex.IsMatch(v, #"^\d+$")).ToArray();
var second = arr.Where(v => Regex.IsMatch(v, #"^\d+-\d+-\d+$")).ToArray();
Console.WriteLine(string.Join(" ", first));
Console.WriteLine(string.Join(" ", second));
Here is a solution that does what you described. It does not use Regex.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
class Program
{
static readonly char[] digits = "0123456789".ToCharArray();
static void Main(string[] args)
{
string[] arr = { "12", "34-2-2", "xyz", "33", "56-3-4", "45-4" };
var pair = ProcessInput(arr);
Console.WriteLine(String.Join(", ", pair.Item1));
Console.WriteLine(String.Join(", ", pair.Item2));
var done = Console.ReadLine();
}
static Tuple<string[], string[]> ProcessInput(string[] input)
{
var l1 = new List<string>();
var l2 = new List<string>();
foreach(var item in input)
{
if (ContainsOnlyIntegers(item))
{
l1.Add(item);
continue; // move on.
}
var parts = item.Split('-');
if (parts.Length == 3 && parts.All(part => ContainsOnlyIntegers(part)))
{
//must have 3 parts, separated by hypens and they are all numbers.
l2.Add(item);
}
}
return Tuple.Create(l1.ToArray(), l2.ToArray());
}
static bool ContainsOnlyIntegers(string input)
{
return input.ToCharArray().All(r => digits.Contains(r));
}
}
}

Loop through array to the Cartesian power n

I want to loop through the array which is the result of the array to the Cartesian power n. https://en.wikipedia.org/wiki/Cartesian_product#n-ary_product
This is what I want to achieve, just with n depth:
int[] array = new int[] { 5, -4, ... }
foreach(int a in array) {
foreach(int b in array) {
foreach(int c in array) {
...
int[] NewArray = new int[] { a, b, c, ... }
In Python this is equivalent to:
from itertools import product
for (NewArray in product(array, repeat=n)):
print(NewArray)
I do not know how I can implement this in C#.
Any help would be highly appreciated. Thanks.
You can implement a cartesian product with a little math and yield return:
static public IEnumerable<T[]> Product<T>(IList<T> items, int repeat) {
var total = (int)Math.Pow(items.Count, repeat);
var res = new T[repeat];
for (var i = 0 ; i != total ; i++) {
var n = i;
for (var j = repeat-1 ; j >= 0 ; j--) {
res[j] = items[n % items.Count];
n /= items.Count;
}
yield return res;
}
}
Calling it like this
foreach (var arr in Product(new[] {"quick", "brown", "fox"}, 3)) {
Console.WriteLine(string.Join("-", arr));
}
produces the following output:
quick-quick-quick
quick-quick-brown
quick-quick-fox
quick-brown-quick
quick-brown-brown
quick-brown-fox
quick-fox-quick
quick-fox-brown
quick-fox-fox
brown-quick-quick
brown-quick-brown
brown-quick-fox
brown-brown-quick
brown-brown-brown
brown-brown-fox
brown-fox-quick
brown-fox-brown
brown-fox-fox
fox-quick-quick
fox-quick-brown
fox-quick-fox
fox-brown-quick
fox-brown-brown
fox-brown-fox
fox-fox-quick
fox-fox-brown
fox-fox-fox
Demo.
you can calculate cartesian product of two arrays like below
string[][] CartesianProduct(string[] arr1, string[] arr2)
{
// for each s1 in arr1, extract arr2,
// then pass s1 and s2 into a newly-made string array.
return arr1.SelectMany(s1 => arr2, (s1, s2) => new string[] { s1, s2 })
.ToArray();
}
Lets say you have two array namely
string[] set1 = new string[] { "a", "b", "c" };
string[] set2 = new string[] { "x", "y", "z" };
make a call to CartesianProduct function which would return the resulting value like below.
var cartesionProduct = CartesianProduct (set1,set2);

Comparing two string arrays in C#

Say we have 5 string arrays as such:
string[] a = {"The","Big", "Ant"};
string[] b = {"Big","Ant","Ran"};
string[] c = {"The","Big","Ant"};
string[] d = {"No","Ants","Here"};
string[] e = {"The", "Big", "Ant", "Ran", "Too", "Far"};
Is there a method to compare these strings to each other without looping through them in C# such that only a and c would yield the boolean true? In other words, all elements must be equal and the array must be the same size? Again, without using a loop if possible.
You can use Linq:
bool areEqual = a.SequenceEqual(b);
Try using Enumerable.SequenceEqual:
var equal = Enumerable.SequenceEqual(a, b);
if you want to get array data that differ from another array you can try .Except
string[] array1 = { "aa", "bb", "cc" };
string[] array2 = { "aa" };
string[] DifferArray = array1.Except(array2).ToArray();
Output:
{"bb","cc"}
If you want to compare them all in one go:
string[] a = { "The", "Big", "Ant" };
string[] b = { "Big", "Ant", "Ran" };
string[] c = { "The", "Big", "Ant" };
string[] d = { "No", "Ants", "Here" };
string[] e = { "The", "Big", "Ant", "Ran", "Too", "Far" };
// Add the strings to an IEnumerable (just used List<T> here)
var strings = new List<string[]> { a, b, c, d, e };
// Find all string arrays which match the sequence in a list of string arrays
// that doesn't contain the original string array (by ref)
var eq = strings.Where(toCheck =>
strings.Where(x => x != toCheck)
.Any(y => y.SequenceEqual(toCheck))
);
Returns both matches (you could probably expand this to exclude items which already matched I suppose)
if (a.Length == d.Length)
{
var result = a.Except(d).ToArray();
if (result.Count() == 0)
{
Console.WriteLine("OK");
}
else
{
Console.WriteLine("NO");
}
}
else
{
Console.WriteLine("NO");
}

Convert string[] to int[] in one line of code using LINQ

I have an array of integers in string form:
var arr = new string[] { "1", "2", "3", "4" };
I need to an array of 'real' integers to push it further:
void Foo(int[] arr) { .. }
I tried to cast int and it of course failed:
Foo(arr.Cast<int>.ToArray());
I can do next:
var list = new List<int>(arr.Length);
arr.ForEach(i => list.Add(Int32.Parse(i))); // maybe Convert.ToInt32() is better?
Foo(list.ToArray());
or
var list = new List<int>(arr.Length);
arr.ForEach(i =>
{
int j;
if (Int32.TryParse(i, out j)) // TryParse is faster, yeah
{
list.Add(j);
}
}
Foo(list.ToArray());
but both looks ugly.
Is there any other ways to complete the task?
Given an array you can use the Array.ConvertAll method:
int[] myInts = Array.ConvertAll(arr, s => int.Parse(s));
Thanks to Marc Gravell for pointing out that the lambda can be omitted, yielding a shorter version shown below:
int[] myInts = Array.ConvertAll(arr, int.Parse);
A LINQ solution is similar, except you would need the extra ToArray call to get an array:
int[] myInts = arr.Select(int.Parse).ToArray();
EDIT: to convert to array
int[] asIntegers = arr.Select(s => int.Parse(s)).ToArray();
This should do the trick:
var asIntegers = arr.Select(s => int.Parse(s));
To avoid exceptions with .Parse, here are some .TryParse alternatives.
To use only the elements that can be parsed:
string[] arr = { null, " ", " 1 ", " 002 ", "3.0" };
int i = 0;
var a = (from s in arr where int.TryParse(s, out i) select i).ToArray(); // a = { 1, 2 }
or
var a = arr.SelectMany(s => int.TryParse(s, out i) ? new[] { i } : new int[0]).ToArray();
Alternatives using 0 for the elements that can't be parsed:
int i;
var a = Array.ConvertAll(arr, s => int.TryParse(s, out i) ? i : 0); //a = { 0, 0, 1, 2, 0 }
or
var a = arr.Select((s, i) => int.TryParse(s, out i) ? i : 0).ToArray();
C# 7.0:
var a = Array.ConvertAll(arr, s => int.TryParse(s, out var i) ? i : 0);
you can simply cast a string array to int array by:
var converted = arr.Select(int.Parse)
var asIntegers = arr.Select(s => int.Parse(s)).ToArray();
Have to make sure you are not getting an IEnumerable<int> as a return
var list = arr.Select(i => Int32.Parse(i));

Categories