Generic method for converting string array into list - c#

I would like to create a function that will return list of type that is specified by me at run time.
I tried something along this line:
public static List<T> GetMyList<T>(string[] itemList)
{
List<T> resultList = new List<T>(itemList.Length);
return resultList.AddRange(itemList);
}
But this doesn't work. Obviously I don't fully understand how to pass a type to be converted to.
Any help would be appreciated it.
Edit:
It looks like that it is not possible, but here is more info. String array will contain numbers and I would like to convert those numbers sometimes into int, sometimes into short.
Idea behind is to have a generic function that will attempt to convert items into whatever type list I tell it.

You need to provide a method to convert a string into a T - you can do this using a Func<string, T>:
public static List<T> GetMyList<T>(string[] itemList, Func<string, T> conversionFunc)
{
return itemList.Select(conversionFunc).ToList();
}
e.g.
List<int> ints = GetMyList(new[] { "1", "2", "3" }, s => int.Parse(s));

A slightly more elegant solution would be to add an extension method to string that automatically calls the parser for type T, like so:
public static class GenericParser {
public static T Parse<T>(this string input) {
var converter = TypeDescriptor.GetConverter(typeof(T));
if ( converter != null ) {
return ( T )converter.ConvertFromString(input);
}
return default(T);
}
}
Then, your conversion function would look something like:
public static List<T> GetMyList<T>(string[] itemList) {
List<T> list = new List<T>();
list.AddRange(Array.ConvertAll<string, T>(itemList, delegate(string s) {
return s.Parse<T>();
}));
return list;
}
And the usage would be:
List<int> integers = GetMyList<int>(new []{"1", "2", "3", "4"});
List<double> doubles = GetMyList<double>(new []{"1.0", "2.0", "3.0", "4.0"});
and so on.

My first thought is that this won't work because not every object type can be constructed from a string. Perhaps you want something with a signature more like:
public static List<T> GetMyList<T>(T[] itemList)
{
List resultList = new List(itemList.Length);
foreach (t in itemList)
{
resultList.add(t);
}
return resultList;
}
(forgive my syntax. I don't have a compiler handy right now to check it.)

this doesn't work because system has no idea how to convert string to generic T. Also even if it is known, it will not work, because C# (prior to 4) doesn't have type covariance. So use either foreach to copy and convert elements one by one or use Select from Linq

Similar to Lee's but more generic...
public static class Tools
{
public static List<TResult> ToList<T, TResult>(
this IEnumerable<T> input,
Func<T, TResult> conversion)
{
return input.Select(conversion).ToList();
}
public static List<TResult> ToList<T, TResult>(
this IEnumerable<T> input,
Func<T, int, TResult> conversion)
{
return input.Select(conversion).ToList();
}
}
class Program
{
static void Main(string[] args)
{
var input = new[] { "1", "2", "3" };
var ret = input.ToList(i => int.Parse(i));
// 1,2,3
var ret2 = input.ToList((i,j) => int.Parse(i) + j * 10);
// 1,12,23
}
}

Related

How to specify a list selection method?

I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which element is chosen, but I'd like to leave it up to the user to decide.
Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?
I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?
This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.
This isn't a GUI app. I'm trying to decide how to design the API.
Specifically, I want to have a field like
public Func<IList<T>, T> SelectElement = list => list.First();
Which would then be used in the method,
public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)
But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.
Edit: full source code
how about this:
public class MyClass
{
public static class C<T>
{
public static Func<IList<T>, T> SelectElement;
}
public int Test(IList<int> list)
{
return C<int>.SelectElement(list);
}
}
static class Program
{
static void Main(string[] args)
{
MyClass.C<char>.SelectElement = xs => xs.First();
MyClass.C<int>.SelectElement = xs => xs.First();
var list = new List<int>(new int[] { 1, 2, 3 });
var c = new MyClass();
var v = c.Test(list);
Console.WriteLine(v);
}
}
Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Simple list.
var list = new List<int> { 1, 2, 3, 4 };
// Try it with first
var result = DoItemSelect(list, Enumerable.First);
Console.WriteLine(result);
// Try it with last
result = DoItemSelect(list, Enumerable.Last);
Console.WriteLine(result);
// Try it with ElementAt for the second item (index 1) in the list.
result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
Console.WriteLine(result);
}
public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
{
// You can do whatever you method does here, selector is the user specified func for
// how to select from the enumerable. Here I just return the result of selector directly.
return selector(enumerable);
}
}
}
If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.
public Func<IList<object>, object> SelectElement = list => list.First();
private T _S<T>(IEnumerable<T> list)
{
return (T)SelectElement(list.Cast<object>().ToList());
}
I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.
This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.
LINQPad code:
void Main()
{
var chars = new List<char>();
var strings = new List<string>();
chars.AddRange(new char[] {'1','2','4','7','8','3'});
strings.AddRange(new string[] {"01","02","09","12","28","52"});
chars.Dump();
strings.Dump();
Func<IList<object>, string> SelectFirst = ( list )
=> list.First().ToString();
Func<IList<object>, string> SelectLast = ( list )
=> list.Last().ToString();
Func<IList<object>, string> SelectRandom = ( list )
=> list.ElementAt( new Random().Next(0, list.Count())).ToString();
SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump();
}
private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{
return func(list);
}

Unbox an Object to Its Type

is there anyway to unbox an object to its real type?
Basically I am given an ArrayList, the array list are actually a list of int or double, or maybe other types ( it can be either, but it is either all int or double, no mix). Now, I will have to return a List<double> or List<int> or other list, depending on what is the real type.
public List<T> ConvertToList<T>(ArrayList arr)
{
var list1 = new List<T>();
foreach(var obj in arr)
{
// how to do the conversion?
var objT = ??
list1.Add(objT);
}
return list1;
}
Any idea?
If you're using .NET 3.5, there's a much easier way to do this:
public List<T> ConvertToList<T>(IEnumerable original)
{
return original.Cast<T>().ToList();
}
(I've generalised the parameter to just IEnumerable as we're not using anything specific to ArrayList here.)
You can use the Convert class.
var objT = (T)Convert.ChangeType(obj, typeof(T));
You can just regular Type Cast like this
public List<T> ConvertToList<T>(ArrayList arr)
{
var list1 = new List<T>();
foreach(var obj in arr)
{
// Like this
list1.Add((T)obj);
}
return list1;
}

How to create a generic extension method?

I want to develop a Generic Extension Method which should arrange the string in alphabetical then by lengthwise ascending order.
I mean
string[] names = { "Jon", "Marc", "Joel",
"Thomas", "Copsey","Konrad","Andrew","Brian","Bill"};
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
What is the way to develop Generic Extension Method?
I tried :
public static class ExtensionOperation
{
public static T[] AlphaLengthWise<T>(this T[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
I received :
Error 1: T does not contain definition for Length
Error 2: can not convert System.Linq.IOrderedEnumerable to T[].
The first error is because Length is a property of the String class while in your generic version the type of the T parameter is not known. It could be any type.
The second error is because you return just the query object but not the actual result. You might need to call ToArray() before returning.
With little modifications you could come up with this:
public static class ExtensionOperation
{
public static IEnumerable<T> AlphaLengthWise<T, L>(
this IEnumerable<T> names, Func<T, L> lengthProvider)
{
return names
.OrderBy(a => lengthProvider(a))
.ThenBy(a => a);
}
}
Which you could use like this:
string[] names = { "Jon", "Marc", "Joel", "Thomas", "Copsey", "Konrad", "Andrew", "Brian", "Bill" };
var result = names.AlphaLengthWise(a => a.Length);
Why do you want to do this generically? Just use
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(this string[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
I think you may be a little confused to the purpose of generics.
Generics are a way to tailor a class or method to a specific type. A generic method or class is designed to work for any type. This is most easily illustrated in the List<T> class, where it can be tailored to be a list of any type. This gives you the type-safety of knowing the list only contains that specific type.
Your problem is designed to work on a specific type, the string type. Generics are not going to solve a problem which involves a specific type.
What you want is a simple (non-generic) Extension Method:
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(
this IEnumerable<string> names)
{
if(names == null)
throw new ArgumentNullException("names");
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Making the argument and the return type IEnumerable<string> makes this a non-generic extension method which can apply to any type implementing IEnumerable<string>. This will include string[], List<string>, ICollection<string>, IQueryable<string> and many more.
I want to develop a Generic Extension Method which should arrange the strings in alphabetical then ...
public static class ExtensionOperation
{
public static IEnumerable<String> AplhaLengthWise(
this IEnumerable<String> names)
{
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Copy how Microsoft does it:
public static class ExtensionOperation {
// Handles anything queryable.
public static IOrderedQueryable<string> AlphaLengthWise(this IQueryable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
// Fallback method for non-queryable collections.
public static IOrderedEnumerable<string> AlphaLengthWise(this IEnumerable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
You want to use IEnumerable<T> instead of T[]. Other than that, you won't be able to use Length of T, since not all types has a Length property. You could modify your extension method to .OrderBy(a => a.ToString().Length)
If you know you'll always be dealing with strings, use IEnumerable<String> rather than IEnumerable<T>, and you'll be able to access the Length property immediately.

Is there a statement to prepend an element T to a IEnumerable<T>

For example:
string element = 'a';
IEnumerable<string> list = new List<string>{ 'b', 'c', 'd' };
IEnumerable<string> singleList = ???; //singleList yields 'a', 'b', 'c', 'd'
I take it you can't just Insert into the existing list?
Well, you could use new[] {element}.Concat(list).
Otherwise, you could write your own extension method:
public static IEnumerable<T> Prepend<T>(
this IEnumerable<T> values, T value) {
yield return value;
foreach (T item in values) {
yield return item;
}
}
...
var singleList = list.Prepend("a");
Since .NET framework 4.7.1 there is LINQ method for that:
list.Prepend("a");
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.prepend?view=netframework-4.7.1
public static class IEnumerableExtensions
{
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> ie, T item)
{
return new T[] { item }.Concat(ie);
}
}
You can roll your own:
static IEnumerable<T> Prepend<T>(this IEnumerable<T> seq, T val) {
yield return val;
foreach (T t in seq) {
yield return t;
}
}
And then use it:
IEnumerable<string> singleList = list.Prepend(element);
This would do it...
IEnumerable<string> singleList = new[] {element}.Concat(list);
If you wanted the singleList to be a List then...
IEnumerable<string> singleList = new List<string>() {element}.Concat(list);
... works too.
Also:
IEnumerable<string> items = Enumerable.Repeat(item, 1).Concat(list);
I find it convenient to be able to prepend multiple items in a chainable fashion. This version takes advantage of extension methods and params.
As a note, this version implicitly allows null, but it's just as easy to change it to throw new NullReferenceException() if that's the desired behavior.
public static class IEnumerableExtensions
{
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] items)
{
return items.Concat(source ?? new T[0]);
}
}
Allows for a very readable syntax for individual items:
GetItems().Prepend(first, second, third);
...and for collections of items:
GetItems().Prepend(GetMoreItems());
Finishing the example in the question results in:
string element = "a";
IEnumerable<string> list = new List<string>{ "b", "c", "d" };
IEnumerable<string> singleList = list.Prepend(element);
No, there's no such built-in statment, statement, but it's trivial to implement such function:
IEnumerable<T> PrependTo<T>(IEnumerable<T> underlyingEnumerable, params T[] values)
{
foreach(T value in values)
yield return value;
foreach(T value in underlyingEnumerable)
yield return value;
}
IEnumerable<string> singleList = PrependTo(list, element);
You can even make it an extension method if C# version allows for.
Just as a reminder - List< T > is not the only type of container. If you find yourself adding elements to the front of the list quite frequently, you can also consider using Stack< T > to implement your container. Once you have a stack
var container = new Stack<string>(new string[] { "b", "c", "d" });
you can always "prepend" an element via
container.Push("a");
and still use the collection as IEnumerable< T > like in
foreach (var s in container)
// do sth with s
besides all the other methods typical for a stack like Pop(), Peek(), ...
Some of the solutions above iterate through the whole IEnumeration< T > just to prepend one element (or more than one in one case). This can be a very expensive operation if your collection contains a large number of elements and the frequency of prepending is relatively high.
Looking at some of the examples, I think I'd prefer to reverse the extension to apply to the object.
public static IEnumerable<T> PrependTo<T>(this T value, IEnumerable<T> values) {
return new[] { value }.Concat(values);
}
Used like
var singleList = element.PrependTo(list);
As pointed out by Niklas & NetMage in the comments.
There is a new built-in Prepend methond in C#.

Generic Map/Reduce List Extensions in C#

I am writing a few extensions to mimic the map and reduce functions in Lisp.
public delegate R ReduceFunction<T,R>(T t, R previous);
public delegate void TransformFunction<T>(T t, params object[] args);
public static R Reduce<T,R>(this List<T> list, ReduceFunction<T,R> r, R initial)
{
var aggregate = initial;
foreach(var t in list)
aggregate = r(t,aggregate);
return aggregate;
}
public static void Transform<T>(this List<T> list, TransformFunction<T> f, params object [] args)
{
foreach(var t in list)
f(t,args);
}
The transform function will cut down on cruft like:
foreach(var t in list)
if(conditions && moreconditions)
//do work etc
Does this make sense? Could it be better?
According to this link Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your World the following are the equivalent in C# under the System.Linq namespace:
map --> Enumerable.Select
reduce --> Enumerable.Aggregate
filter --> Enumerable.Where
These look very similar to extensions in Linq already:
//takes a function that matches the Func<T,R> delegate
listInstance.Aggregate(
startingValue,
(x, y) => /* aggregate two subsequent values */ );
//takes a function that matches the Action<T> delegate
listInstance.ForEach(
x => /* do something with x */);
Why is the 2nd example called Transform? Do you intend to change the values in the list somehow? If that's the case you may be better off using ConvertAll<T> or Select<T>.
I would use the built in Func delegates instead. This same code would work on any IEnumerable. Your code would turn into:
public static R Reduce<T,R>(this IEnumerable<T> list, Func<T,R> r, R initial)
{
var aggregate = initial;
foreach(var t in list)
aggregate = r(t,aggregate);
return aggregate;
}
public static void Transform<T>(this IEnumerable<T> list, Func<T> f)
{
foreach(var t in list)
f(t);
}
You might want to add a way to do a map but return a new list, instead of working on the list passed in (and returning the list can prove useful to chain other operations)... perhaps an overloaded version with a boolean that indicates if you want to return a new list or not, as such:
public static List<T> Transform<T>(this List<T> list, TransformFunction<T> f,
params object [] args)
{
return Transform(list, f, false, args);
}
public static List<T> Transform<T>(this List<T> list, TransformFunction<T> f,
bool create, params object [] args)
{
// Add code to create if create is true (sorry,
// too lazy to actually code this up)
foreach(var t in list)
f(t,args);
return list;
}
I would recommend to create extension methods that internally use LinQ like this:
public static IEnumerable<R> Map<T, R>(this IEnumerable<T> self, Func<T, R> selector) {
return self.Select(selector);
}
public static T Reduce<T>(this IEnumerable<T> self, Func<T, T, T> func) {
return self.Aggregate(func);
}
public static IEnumerable<T> Filter<T>(this IEnumerable<T> self, Func<T, bool> predicate) {
return self.Where(predicate);
}
Here some example usages:
IEnumerable<string> myStrings = new List<string>() { "1", "2", "3", "4", "5" };
IEnumerable<int> convertedToInts = myStrings.Map(s => int.Parse(s));
IEnumerable<int> filteredInts = convertedToInts.Filter(i => i <= 3); // Keep 1,2,3
int sumOfAllInts = filteredInts.Reduce((sum, i) => sum + i); // Sum up all ints
Assert.Equal(6, sumOfAllInts); // 1+2+3 is 6
(See https://github.com/cs-util-com/cscore#ienumerable-extensions for more examples)

Categories

Resources