Visual C# converting custom IEnumerable to string[] - c#

I am writing a plugin code in C# and there is a custom IEnumerable that is in fact an array of strings. However no string operations can be done on the array elements because they are not of the type <string>. But I need them to be strings and I have to operate on them as strings.
So I have added these 2 lines of code to turn the array into string:
var arrayRawSourceText = EditorController.ActiveDocument.ActiveSegmentPair.Source.AllSubItems.ToArray();
string[] arraySourceText = new string[arrayRawSourceText.Length];
for (int i = 0; i < arrayRawSourceText.Length; i++) { arraySourceText[i] = arrayRawSourceText[i].ToString(); }
Only two lines, yet I wonder if there is a simpler way of converting the array to <string>. Like a lambda expression or any other way to make this simpler.

If AllSubItems implement IEnumerable I guess this code snippet should work :
var arraySourceText = EditorController.ActiveDocument
.ActiveSegmentPair
.Source
.AllSubItems
.Select(t => t.ToString())
.ToArray();

I have seen you already accepted an answer, But for further searchers maybe this will fit too:
var arraySourceText = EditorController.ActiveDocument
.ActiveSegmentPair
.Source
.AllSubItems
.Cast<string>()
.ToArray();

Related

How to extract a fragment of an element in an existing array to generate a new array

I have an array :
string[] arr = new string[2]
arr[0] = "a=01"
arr[1] = "b=02"
How can I take those number out and make a new array to store them? What I am expecting is :
int [] newArr = new int[2]
Inside newArr, there are 2 elements, one is '01' and the other one is '02' which both from arr.
Another way besides Substring to get the desired result is to use String.Split on the = character. This is assuming the string will always have the format of letters and numbers, separated by a =, with no other = characters in the input string.
for (var i = 0; i < arr.Length; i++)
{
// Split the array item on the `=` character.
// This results in an array of two items ("a" and "01" for the first item)
var tmp = arr[i].Split('=');
// If there are fewer than 2 items in the array, there was not a =
// character to split on, so continue to the next item.
if (tmp.Length < 2)
{
continue;
}
// Try to parse the second item in the tmp array (which is the number
// in the provided example input) as an Int32.
int num;
if (Int32.TryParse(tmp[1], out num))
{
// If the parse is succesful, assign the int to the corresponding
// index of the new array.
newArr[i] = num;
}
}
This can be shortened in a lambda expression like the other answer like so:
var newArr = arr.Select(x => Int32.Parse(x.Split('=')[1])).ToArray();
Though doing it with Int32.Parse can result in an exception if the provided string is not an integer. This also assumes that there is a = character, with only numbers to the right of it.
Take a substring and then parse as int.
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
As other answers have noted, it's quite compact to use linq. PM100 wrote:
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
You asked what x was.. that linq statement there is conceptually the equivalent of something like:
List<int> nums = new List<int>();
foreach(string x in arr)
nums.Add(Int32.Parse(x.Substring(2);
var newArr = nums.ToArray();
It's not exactly the same, internally linq probably doesn't use a List, but it embodies the same concept - for each element (called x) in the string array, cut the start off it, parse the result as an int, add it to a collection, convert the collection to an array
Sometimes I think linq is overused; here probably efficiencies could be gained by directly declaring an int array the size of the string one and filling it directly, rather than adding to a List or other collection, that is later turned into an int array. Proponents of either style could easily be found; linq is compact and makes relatively trivial work of more long hand constructs such as loops within loops within loops. Though not necessarily easy to work out for those unfamiliar with how to read it it does bring a certain self documenting aspect to code because it uses English words like Any, Where, Distinct and these more quickly convey a concept than does looking at a loop code that exits early when a test returns true (Any) or builds a dictionary/hashset from all elements and returns it (Distinct)

Array as property. Looking for simpler way to fill an array

I am pretty new to C# and I see a lot of code where I'm not quite familiar with the syntax. So I was wondering if there's some simpler way of doing what I did here:
I have a class with various properties and functions. One of them is public int gettypeforitem(int i) which returns an integer.
I want to define a property of type int[] that returns an array of the types of all items.
I come from C++, so the following code seems logic to me, but I was wondering if there's a more "straight forward" way in doing this in C#.
Thank you!
public int[] type
{
get
{
List<int> _list = new List<int>();
for(uint i=0; i<NumberOfItems;i++)
_list.Add(gettypeforitem(i));
return _list.ToArray();
}
}
LINQ is the way forward here, I'd say:
public int[] Types => Enumerable.Range(0, NumberOfItems)
.Select(i => GetTypeForItem(i))
.ToArray();
I've changed the names to follow .NET naming conventions, and this is using C# 6's expression-bodied property syntax.
As this is doing a relatively large amount of work for a property - generating a new array every call, for a start - you might want to consider making it a method instead:
public int[] GetTypes() => Enumerable.Range(0, NumberOfItems)
.Select(i => GetTypeForItem(i))
.ToArray();
As noted in comments elsewhere, you may be able to use a method group conversion for the argument to the Select method:
public int[] GetTypes() => Enumerable.Range(0, NumberOfItems)
.Select(GetTypeForItem)
.ToArray();
The exact rules for when method group conversions are valid as arguments always elude me, so I won't try to summarise them here. (They've changed over time, too.)
public int[] type
{
get
{
return Enumerable.Range(0, NumberOfItems).Select(gettypeforitem).ToArray();
}
}
Update:
As suggested in comments its better to keep C# naming standards:
public int[] Types
{
get
{
return Enumerable.Range(0, NumberOfItems).Select(getTypeForItem).ToArray();
}
}
Since you know the number of items, you can create an array straight away:
int[] _arr = new int[NumberOfItems];
for(uint i=0; i<NumberOfItems;i++)
_arr[i] = gettypeforitem(i);
return _arr;
Or if you don't care about the overhead:
Enumerable.Range(0, NumberOfItems).Select(gettypeforitem).ToArray();
Does the return type of the property have to be really an array? If not, you can alternatively also use this:
public IEnumerable<int> type
{
get
{
for(uint i=0; i<NumberOfItems;i++)
yield return gettypeforitem(i);
}
}
and then:
myObject.type.ToArray();

Performing function on each array element, returning results to new array

I'm a complete Linq newbie here, so forgive me for a probably quite simple question.
I want to perform an operation on every element in an array, and return the result of each of these operations to a new array.
For example, say I have an array or numbers and a function ToWords() that converts the numbers to their word equivalents, I want to be able to pass in the numbers array, perform the ToWords() operation on each element, and pass out a string[]
I know it's entirely possible in a slightly more verbose way, but in my Linq adventures I'm wondering if it's doable in a nice one-liner.
You can use Select() to transform one sequence into another one, and ToArray() to create an array from the result:
int[] numbers = { 1, 2, 3 };
string[] strings = numbers.Select(x => ToWords(x)).ToArray();
It's pretty straight forward. Just use the Select method:
var results = array.Select(ToWords).ToArray();
Note that unless you need an array you don't have to call ToArray. Most of the time you can use lazy evaluation on an IEnumerable<string> just as easily.
There are two different approaches - you can use Select extension method or you can use select clause:
var numbers = new List<int>();
var strings1 = from num in numbers select ToWords(num);
var strings2 = numbers.Select(ToWords);
both of them will return IEnumerable<>, which you can cast as you need (for example, with .ToArray() or .ToList()).
You could do something like this :
public static string[] ProcessStrings(int[] intList)
{
return Array.ConvertAll<int, string>(intList, new Converter<int, string>(
delegate(int number)
{
return ToWords();
}));
}
If it is a list then :
public static List<string> ProcessStrings(List<int> intList)
{
return intList.ConvertAll<string>(new Converter<int, string>(
delegate(int number)
{
return ToWords();
}));
}
Straight simple:
string[] wordsArray = array.ToList().ConvertAll(n => ToWords(n)).ToArray();
If you are OK with Lists, rather than arrays, you can skip ToList() and ToArray().
Lists are much more flexible than arrays, I see no reason on earth not to use them, except for specific cases.

Looping over jagged arrays in c# --- using foreach instead of for?

I'm working on a project, and I find myself repeatedly looping over a jagged array using nested for loops. I'm wondering if there might be a neater way of doing it using foreach?
Here's what I mean:
for (int ii = 0; ii < xDimension; ii++)
{
for (int jj = 0; jj < yDimension; jj++)
{
OutputArray[ii][jj] = someFunction(InputArray[ii][jj]);
}
}
Note that I'm using Jagged arrays even though my data is of fixed size because jagged arrays are faster than multidimensional arrays. Unfortunately speed is an issue with this project so unfortunately performance will outweigh my own OCD coding desires.
Is there a way to do this with foreach that avoids the nested for loops but puts the output data in the correct place in the OutputArray? Wwould there be any benefit/loss from doing so (if it is possible) other than having slightly neater code?
If you really want to create a jagged array as the result, you could use Array.ConvertAll twice:
var result = Array.ConvertAll(input,
array => Array.ConvertAll(array, SomeFunction));
This is slightly more efficient than using Select/ToArray from LINQ, as it knows it's converting an array to another array, so can create the target arrays immediately. Using Select followed by ToArray requires the results to be built up gradually, as if you were putting them into a List<T>, copying them when the buffer is exhausted - and then "right-sizing" the array at the end.
On the other hand, using LINQ (as per Daniel's answer) would probably be more idiomatic these days... and the performance difference will usually be insignificant. I thought I'd give this as another option :)
(Note that this creates new arrays, ignoring the existing OutputArray... I'm assuming you can get rid of the creation of the existing OutputArray, although that may not be the case...)
The following code is "neater":
OutputArray = InputArray.Select(x => x.Select(y => someFunction(y)).ToArray())
.ToArray();
But I would just go with the loops, because this LINQ version has a significant disadvantage: It creates new arrays instead of using the existing ones in OutputArray. This argument is moot if you create OutputArray right before the loop you showed us.
Furthermore, it is quite a lot harder to read.
You could get data out of the jagged array more easily using a foreach, but as you wouldn't have variables indicating the indexes you wouldn't be able to set a value of the array very effectively, like you do in your example.
If you just wanted to read the values though, you can do this:
foreach(int n in OutputArray.SelectMany(array=>array))
{
Console.WriteLine(n);
}
The SelectMany is needed to flatten the sequence, so that instead of being a sequence of sequences it is just a single sequence.
You can even get the indices out with LINQ:
foreach (var t in InputArray.SelectMany(
(inner, ii) => inner.Select((val, jj) => new { val, ii, jj })))
{
OutputArray[t.ii][t.jj] = someFunction(t.val);
}
but, to be honest, the twin-for-loop construct is a lot more maintainable.
Another alternative, just for fun:
foreach (var item in InputArray.SelectMany(x => x).Select((value, index) => new {value, index}))
{
var x = item.index / yDimension;
var y = item.index % yDimension;
OutputArray[x][y] = someFunction(item.value);
}
I'd just stick with the nested loops, though.

c# Array.ForEach alternative that replaces elements

Is there a standard function I can use that iterates over an array similarly to ForEach, applying a function to each element and replacing it in the array with the result?
Something like the following, but where dimension powers afterwards contains the results of IntPow(2, i) on each element.
dimensionPowers = Enumerable.Range(0, dimensions + 1).ToArray();
Array.ForEach(dimensionPowers,
(i) => IntPow(2, i));
(I know I can iterate over the array with a for loop - I'm just wondering if there's a more concise alternative).
The MSDN docs says that the designers deliberately did not put in a "ForEach" with an Array due to the fact that: 1) it is trivial to write, 2) exactly your problem -- people will get confused whether the original array is modified or not.
Most of the ForEach types of array iterator implementation (you actually need a "map" function) returns a new instance of an array. For example, you can use LINQ:
newArray = dimensionPowers.Select(i => IntPow(2,i)).ToArray();
or better:
dimensionPowers = Enumerable.Range(0, dimensions + 1).Select(i => IntPow(2,i)).ToArray();
However, if you want to modify the original array in-place, there is the good old for-loop:
for (int i=0; i < dimensionPowers.Length; i++) { dimensionPowers[i] = IntPow(2,i); }
The designers for .NET forces you to use these different methods just so that you'll know when an array is modified.
If you want to implement your in-place modification, you can create an extension method:
static void ForEachModifyInPlace<T> (this Array<T> array, Func<T,T> map_action) {
for (int i=0; i < array.Length; i++) { array[i] = map_action(array[i]); }
}
I don't think you can do it much more concisely (using existing methods).
You could collapse the two steps in one:
dimensionPowers = Enumerable.Range(0, dimensions + 1).Select(i => IntPow(2, i)).ToArray();

Categories