"I have a List of objects with a property "CustomizationName".
I want to join by a comma the values of that property, i.e.; something like this:
List<MyClass> myclasslist = new List<MyClass>();
myclasslist.Add(new MyClass { CustomizationName = "foo"; });
myclasslist.Add(new MyClass { CustomizationName = "bar"; });
string foo = myclasslist.Join(",", x => x.CustomizationName);
Console.WriteLine(foo); // outputs 'foo,bar'
string foo = String.Join(",", myClasslist.Select(m => m.CustomizationName).ToArray());
If you want, you can turn this into an extension method:
public static class Extensions
{
public static string ToDelimitedString<T>(this IEnumerable<T> source, Func<T, string> func)
{
return ToDelimitedString(source,",",func);
}
public static string ToDelimitedString<T>(this IEnumerable<T> source, string delimiter, Func<T, string> func)
{
return String.Join(delimiter, source.Select(func).ToArray());
}
}
Usage:
public class MyClass
{
public string StringProp { get; set; }
}
.....
var list = new List<MyClass>();
list.Add(new MyClass { StringProp = "Foo" });
list.Add(new MyClass { StringProp = "Bar" });
list.Add(new MyClass { StringProp = "Baz" });
string joined = list.ToDelimitedString(m => m.StringProp);
Console.WriteLine(joined);
Related
I have a collection of objects like the example Foo below:
public class Foo
{
public long Id { get; set; }
public IEnumerable<Foo> FooParents { get; set; }
public IEnumerable<Foo> FooChildren { get; set; }
}
These objects are related to each other by the properties FooParents and FooChildren.
How can I effectively detect a circular dependency for a specific Foo?
I know, what to do in case of one-to-many, but in case of many-to-many, I am a little bit confused.
:(
Thank you!
Here is an implementation with some tests.
This is a generic solution that performs a Depth-First Search
with behaviour specialised to your problem domain. It keeps a history of visited nodes in the soFar hash set, completing when either a duplicate is encountered or the paths along the specified branches are exhausted.
A duplicate indicates a circular relationship.
This extension method must be supplied with a number delegates. First a key selector that yields a unique identifier for each item. Then any number of axis selectors that represent the branches, upon which, the object graph extends.
The interesting extension method is here,
public static bool IsCircular<T, K>(
this T item,
Func<T, K> keySelector,
params Func<T, IEnumerable<T>>[] axes)
{
var soFar = new HashSet<K>();
soFar.Add(keySelector(item));
return axes.Any(axis =>
axis(item).Any(next => IsCircularOnAxis(
next,
keySelector,
axis,
soFar)));
}
private static bool IsCircularOnAxis<T, K>(
T item,
Func<T, K> keySelector,
Func<T, IEnumerable<T>> axisSelector,
HashSet<K> soFar)
{
var key = keySelector(item);
if(soFar.Contains(key))
{
return true;
}
soFar.Add(key);
return axisSelector(item).Any(next =>
IsCircularOnAxis(
next,
keySelector,
axisSelector,
soFar));
}
In this case of Foo, the extension method would be called like this,
someFoo.IsCircular(
foo => foo.Id, /*The key selector*/
foo => foo.FooParents, /*The parent axis selector*/
foo => foo.FooChildren); /*The child axis selector*/
The full working example is here, with some tests for Foo.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var soloFoo = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
Console.WriteLine($"soloFoo isCircular:{soloFoo.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
var selfParent = new Foo
{
Id = 1,
FooChildren = Enumerable.Empty<Foo>(),
};
selfParent.FooParents = new[] { selfParent };
Console.WriteLine($"selfParent isCircular:{selfParent.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
var selfChild = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
};
selfChild.FooChildren = new[] { selfChild };
Console.WriteLine($"selfChild isCircular:{selfChild.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
var parentFoo = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
var childFoo = new Foo
{
Id = 2,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
var middleFoo = new Foo
{
Id = 3,
FooParents = new[] { parentFoo },
FooChildren = new[] { childFoo },
};
Console.WriteLine($"middleFoo isCircular:{middleFoo.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
var ringFooA = new Foo
{
Id = 1,
};
var ringFooB = new Foo
{
Id = 2,
FooParents = new[] { ringFooA },
};
var ringFooC = new Foo
{
Id = 3,
FooParents = new[] { ringFooB },
FooChildren = new[] { ringFooA },
};
ringFooA.FooParents = new[] { ringFooC };
ringFooA.FooChildren = new[] { ringFooB };
ringFooB.FooChildren = new[] { ringFooC };
Console.WriteLine($"ringFooA isCircular:{ringFooA.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
Console.WriteLine($"ringFooB isCircular:{ringFooB.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
Console.WriteLine($"ringFooC isCircular:{ringFooC.IsCircular(foo => foo.Id, foo => foo.FooParents, foo => foo.FooChildren)}");
}
}
public static class Extensions
{
public static bool IsCircular<T, K>(
this T item,
Func<T, K> keySelector,
params Func<T, IEnumerable<T>>[] axes)
{
var soFar = new HashSet<K>();
soFar.Add(keySelector(item));
return axes.Any(axis =>
axis(item).Any(next => IsCircularOnAxis(
next,
keySelector,
axis,
soFar)));
}
private static bool IsCircularOnAxis<T, K>(
T item,
Func<T, K> keySelector,
Func<T, IEnumerable<T>> axisSelector,
HashSet<K> soFar)
{
var key = keySelector(item);
if(soFar.Contains(key))
{
return true;
}
soFar.Add(key);
return axisSelector(item).Any(next =>
IsCircularOnAxis(
next,
keySelector,
axisSelector,
soFar));
}
}
public class Foo
{
public long Id { get; set; }
public IEnumerable<Foo> FooParents { get; set; }
public IEnumerable<Foo> FooChildren { get; set; }
}
If I have a simple class that looks like this:
public string Param1 { get; set; }
public string Param2 { get; set; }
public SimpleClass (string a, string b) { Param1 = a; Param2 = b; }
List of string array returned from another class:
var list = new List<string[]> {new[] {"first", "second"}, new[] {"third", "fourth"}};
Is there a more efficient way using C# to end up with List<SimpleClass> without doing something like:
var list1 = new List<SimpleClass>();
foreach (var i in list)
{
var data = new SimpleClass(i[0], i[1]);
list1.Add(data);
}
You can use Linq:
var simpleClassList = originalList.Select(x => new SimpleClass(x[0], x[1])).ToList()
As was said by #rualmar you can use linq. But you also can overload implicit operator.
For example
public static implicit operator SimpleClass(string[] arr)
{
return new SimpleClass(arr[0], arr[1]);
}
and after that you can write this
var list = new List<SimpleClass> { new[] { "first", "second" }, new[] { "third", "fourth" } };
I'm messing around with generics and IEnumerable abit, but i'm kindof stuck.
Here's what i'm trying to do:
I want to have a method that returns any collection type - that implements IEnumerable (?) - (so e.g: List, Stack, Queue, ...)
furthermore, i want to be able to return any collection type, of any datatype.
so i want this method to be able to return a List<string>, as well as a Stack<int>, as well as a List<double>... etc etc.
public IEnumerable<T> returnSomething()
{
Stack<int> stackOfInts = new Stack<int>();
List<string> listOfStrings = new List<string>();
return stackOfInts;
}
this is what i've tried so far. this however doesn't work, i get this error:
Cannot implicitly convert type 'System.Collections.Generic.Stack<int>' to 'System.Collections.Generic.IEnumerable<T>'. An explicit conversion exists (are you missing a cast?)
however, if i replace the IEnumerable<T> in the method signature to IEnumerable<int> , i can return any collection of type int. This however means, that now i can't return the ListOfStrings anymore.
would appreciate any suggestions or ideas :)
You need to add a generic type parameter to your method:
public IEnumerable<T> ReturnSomething<T>()
{
Stack<T> stackOfT = new Stack<T>();
return stackOfT;
}
The type parameter appears after the method name, but before the parameters. It is also possible to have a method with more than one type parameter.
When you call the method you can specify the type:
IEnumerable<int> myInts = ReturnSomething<int>();
The trick is to declare <T> right, if you define generic <T>, then you have to stick to it in your methods, so if you have IEnumerable<T> then elsewhere in your method you must use <T> and not <int> or any other type.
It is only latter when you actually use you generic type you substitute generic <T> for a real type.
See a sample
class Foo<T>
{
public IEnumerable<T> GetList()
{
return new List<T>();
}
public IEnumerable<T> GetStack()
{
return new Stack<T>();
}
}
class Program
{
static void Main(string[] args)
{
Foo<int> foo = new Foo<int>();
IEnumerable<int> list = foo.GetList();
IEnumerable<int> stack = foo.GetStack();
Foo<string> foo1 = new Foo<string>();
IEnumerable<string> list1 = foo1.GetList();
IEnumerable<string> stack1 = foo1.GetStack();
}
}
public IEnumerable<T> returnSomething()
{
Stack<int> stackOfInts = new Stack<int>();
return (IEnumerable<T>) stackOfInts;
}
The type parameter needs to be specified by the caller somewhere.
Either when instantiating a generic class:
public class MyClass<T>
{
public IEnumerable<T> returnSomething()
{
Stack<T> stackOfTs = new Stack<T>();
List<T> listOfTs = new List<T>();
return stackOfTs;
}
}
var v = new MyClass<int>();
foreach(var item in v.returnSomething())
{
}
Or when calling a generic method of a non-generic class:
public class MyClass
{
public IEnumerable<T> returnSomething<T>()
{
Stack<T> stackOfTs = new Stack<T>();
List<T> listOfTs = new List<T>();
return stackOfTs;
}
}
var v = new MyClass();
foreach(var item in v.returnSomething<int>())
{
}
For more help full structure given below ...
my model is
public class Student
{
public int studentId { get; set; }
public string studentName { get; set; }
public string subject { get; set; }
public string studentClass { get; set; }
public int RollNumber { get; set; }
}
IEnumerable return datalist
public static IEnumerable<Student> ReturnSomething()
{
IList<Student> studentList = new List<Student>()
{
new Student()
{studentId = 1, studentName = "Bill", subject = "Science", studentClass = "nine", RollNumber = 01},
new Student()
{studentId = 2, studentName = "Steve", subject = "Arts", studentClass = "ten", RollNumber = 03},
new Student()
{studentId = 3, studentName = "Ram", subject = "Commerce", studentClass = "nine", RollNumber = 05},
new Student()
{studentId = 1, studentName = "Moin", subject = "Science", studentClass = "ten", RollNumber = 06}
};
return studentList;
}
and last one is access code
Student student = new Student();
IEnumerable<Student> studentList = ReturnSomething();
foreach (Student VARIABLE in studentList)
{
student.studentName += VARIABLE.studentName + " "+ "Class= ";
student.studentClass += VARIABLE.studentClass + " ";
}
Console.WriteLine(student.studentName + student.studentClass);
Console.ReadKey();
Yes you can return any type if you change IEnumerable<T> to IEnumerable<dynamic>
like this:
public IEnumerable<dynamic> returnSomething()
{
.....
When I have 2 List<string> objects, then I can use Intersect and Except on them directly to get an output IEnumerable<string>. That's simple enough, but what if I want the intersection/disjuction on something more complex?
Example, trying to get a collection of ClassA objects which is the result of the intersect on ClassA object's AStr1 and ClassB object's BStr; :
public class ClassA {
public string AStr1 { get; set; }
public string AStr2 { get; set; }
public int AInt { get; set; }
}
public class ClassB {
public string BStr { get; set; }
public int BInt { get; set; }
}
public class Whatever {
public void xyz(List<ClassA> aObj, List<ClassB> bObj) {
// *** this line is horribly incorrect ***
IEnumberable<ClassA> result =
aObj.Intersect(bObj).Where(a, b => a.AStr1 == b.BStr);
}
}
How can I fix the noted line to achieve this intersection.
MoreLINQ has ExceptBy. It doesn't have IntersectBy yet, but you could easily write your own implementation, and possibly even contribute it to MoreLINQ afterwards :)
It would probably look something like this (omitting error checking):
public static IEnumerable<TSource> IntersectBy<TSource, TKey>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> keyComparer)
{
HashSet<TKey> keys = new HashSet<TKey>(first.Select(keySelector),
keyComparer);
foreach (var element in second)
{
TKey key = keySelector(element);
// Remove the key so we only yield once
if (keys.Remove(key))
{
yield return element;
}
}
}
If you wanted to perform an intersection on two completely different types which happened to have a common property type, you could make a more general method with three type parameters (one for first, one for second, and one for the common key type).
x ∈ A ∩ B if and only if x ∈ A and x ∈ B.
So, for each a in aObj, you can check if a.AStr1 is in the set of BStr values.
public void xyz(List<ClassA> aObj, List<ClassB> bObj)
{
HashSet<string> bstr = new HashSet<string>(bObj.Select(b => b.BStr));
IEnumerable<ClassA> result = aObj.Where(a => bstr.Contains(a.AStr1));
}
this code:
public IEnumerable<ClassA> xyz(List<ClassA> aObj, List<ClassB> bObj)
{
IEnumerable<string> bStrs = bObj.Select(b => b.BStr).Distinct();
return aObj.Join(bStrs, a => a.AStr1, b => b, (a, b) => a);
}
has passed the following test:
[TestMethod]
public void PropertyIntersectionBasedJoin()
{
List<ClassA> aObj = new List<ClassA>()
{
new ClassA() { AStr1 = "a" },
new ClassA() { AStr1 = "b" },
new ClassA() { AStr1 = "c" }
};
List<ClassB> bObj = new List<ClassB>()
{
new ClassB() { BStr = "b" },
new ClassB() { BStr = "b" },
new ClassB() { BStr = "c" },
new ClassB() { BStr = "d" }
};
var result = xyz(aObj, bObj);
Assert.AreEqual(2, result.Count());
Assert.IsFalse(result.Any(a => a.AStr1 == "a"));
Assert.IsTrue(result.Any(a => a.AStr1 == "b"));
Assert.IsTrue(result.Any(a => a.AStr1 == "c"));
}
i try to compare two class comp1,comp2 i used method below: ComparerCollection(array_X, array_Y); but there are errors below. Arraylist generated from Ilist. how can i do that?
namespace GenericCollecitonComparer
{
class Program
{
static void Main(string[] args)
{
myClass comp1 = new myClass() { ID = 1, Name = "yusuf" };
myClass comp2 = new myClass() { ID = 1, Name = "yusufk" };
Comparer com = new Comparer(comp1, comp2);
Console.ReadKey();
}
}
public class Comparer
{
public Comparer(myClass x, myClass y)
{
PropertyInfo[] propInfo_X = x.GetType().GetProperties();
PropertyInfo[] propInfo_Y = y.GetType().GetProperties();
ArrayList array_X = new ArrayList();
ArrayList array_Y = new ArrayList();
foreach (PropertyInfo pi in propInfo_X)
array_X.Add(pi.GetValue(x, null));
foreach (PropertyInfo pi in propInfo_Y)
array_Y.Add(pi.GetValue(y, null));
// ComparerCollection(array_X, array_Y); --> Error below
}
public bool ComparerCollection<T>(IList<T> xlist, IList<T> ylist)
{
return xlist.SequenceEqual(ylist);
}
}
public class myClass
{
public int ID { get; set; }
public string Name { get; set; }
}
}
/* Error 1 The type arguments for method '
* GenericCollecitonComparer.Comparer.ComparerCollection<T>(System.Collections.Generic.IList<T>, System.Collections.Generic.IList<T>)'
* cannot be inferred from the usage. Try specifying the type arguments explicitly.
*
*/
The error you receive is due to the fact ArrayList is not a generic class. You can use List<object> instead to make it work.
An alternative implementation:
public class Comparer
{
public bool AreEqual { get; private set; }
public Comparer(myClass x, myClass y)
{
var xProperties = x.GetType().GetProperties();
var yProperties = y.GetType().GetProperties();
var xPropertiesValues = xProperties.Select(pi => pi.GetValue(x, null));
var yPropertiesValues = yProperties.Select(pi => pi.GetValue(y, null));
AreEqual = xPropertiesValues.SequenceEqual(yPropertiesValues);
}
}
And a usage example:
[Test]
public void UsageExample()
{
myClass comp1 = new myClass() { ID = 1, Name = "yusuf" };
myClass comp2 = new myClass() { ID = 1, Name = "yusufk" };
myClass comp3 = new myClass() { ID = 1, Name = "yusuf" };
Comparer comparerOf1And2 = new Comparer(comp1, comp2);
Assert.IsFalse(comparerOf1And2.AreEqual);
Comparer comparerOf1And3 = new Comparer(comp1, comp3);
Assert.IsTrue(comparerOf1And3.AreEqual);
}