using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<A> l = new List<A>();
l.Add(new A("q"));
l.Union(new[] {new A("w"), new A("E")}, new AComparer());
Console.Write(l.Count);
}
}
public class A
{
public String b;
public A(String x)
{
b = x;
}
}
public class AComparer : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
return x != null && y != null && x.b.Equals(y.b);
}
public int GetHashCode(A obj)
{
return 0;
}
}
Unable to figure out how to make the list size go 3? I tried looking up https://msdn.microsoft.com/en-us/library/bb341731(v=vs.110).aspx but unable to figure out if I'm missing anything
Union isn't a member of list, but is an extension on IEnumerable - part of Linq. This means it's pure and doesn't affect the state of the list, but returns a new Enumeration. So you could do
l = l.Union(otherL).ToList();
Related
My assignment is to have a functionality which enables app user to sort RegisteredUser objects according to their filed/property values.
Assistant class inherits RegisteredUser. I would like somehow to be able to utilize lambdas and LINQ and to sort List<Assistants>. Is there a way to achieve this?
public abstract class RegisteredUser
{
protected int id;
protected bool active;
protected string name;
//other fields and methods
public static IComparer sortUsersByName(Order order)
{
return (IComparer)new nameFieldComparator(order);
}
private class nameFieldComparator : IComparer
{
private Order direction;
public nameFieldComparator(Order direction)
{
this.direction = direction;
}
public int Compare(object x, object y)
{
if (x != null && y != null)
{
RegisteredUser user1 = (RegisteredUser)x;
RegisteredUser user2 = (RegisteredUser)y;
return (int)this.direction * String.Compare(user1.Name, user2.Name);
}
else throw new ArgumentNullException("Objects cannot be compared!");
}
}
}
My point of reference was How to use IComparer. I was trying different things, non worked.
Assistant a = new Assistant();
a.SetId(5);
a.Active = true;
a.Name = "asdasd";
Assistant f = new Assistant();
f.SetId(6);
f.Active = true;
f.Name = "asdf";
Assistant c = new Assistant();
c.Name = "a";
c.SetId(2);
List<RegisteredUser> l = new List<RegisteredUser>();
l.Add(a);
l.Add(f);
l.Add(c);
//list.Sort((x, y) => RegisteredUser.sortUsersByName()); of course, doesn't work...
List<Assistant> l = l.OrderBy() //tried bunch of ideas, but cannot get the syntax right
P.S. I am new to programming and c#
try this using Linq and lambdas:
List<RegisteredUser> l = new List<RegisteredUser>();
l.Add(a);
l.Add(f);
l.Add(c);
var sortedList = l.OrderBy(x => x.Name).ToList();
This is a simple implementation of IComparable:
public abstract class RegisteredUser : IComparable
{
public string Name { get; set; }
// other properties
public int CompareTo(object obj)
{
if (obj is RegisteredUser user)
return this.Name.CompareTo(user.Name);
return 1;
}
}
public class Assistant : RegisteredUser
{
}
This is how to use it:
var users = new List<RegisteredUser>();
users.Add(new Assistant() { Name = "John" });
users.Add(new Assistant() { Name = "Joe" });
users.Sort();
The sorting method must have access to your implementation of IComparer, that means nameFieldComparator needs to be a public class in this case.
Here is example of how to sort array of objects by it's fields. I need to create function which will do same thing but WITHOUT Linq, Generics or any other classes.
p.s You can add methods in Test class to compare fields.
using System;
using System.Linq;
class Test {
public int Count;
public int Sum;
}
class Program {
static void Main() {
Test a1 = new Test() {
Count = 1 ,
Sum = 20
};
Test a2 = new Test() {
Count = 2 ,
Sum = 10
};
Test a3 = new Test() {
Count = 3 ,
Sum = 30
};
var arr = new Test[] { a1, a2, a3};
var result = arr.OrderBy(n => n.Count).ToList();
foreach (var item in result) {
Console.WriteLine(item.Count);
}
}
static void MyOrder() {
//function which will sort passed array of objects by fields
}
}
One method is to use Array.Sort() static method. But if you want to use it, you class must implement IComparable interface, for example:
class Test : IComparable
{
public int Count;
public int Sum;
public int CompareTo(object obj)
{
if (!(obj is Test))
throw new ArgumentException("You can't compare two objects of different types!");
var test = (Test)obj;
if (test.Count < this.Count) return 1;
else if (test.Count > this.Count) return -1;
else return 0;
}
}
And then code would become:
var arr = new Test[] { a1, a3, a2 };
Array.Sort(arr);
EDIT:
If you want to change ordering field at runtime, you can use IComparer interface as folloing:
public class Test
{
public int Count;
public int Sum;
}
public class TestComparerBySum : IComparer<Test>
{
public int Compare(Test x, Test y)
{
if (x.Sum > y.Sum) return 1;
else if (x.Sum < y.Sum) return -1;
else return 0;
}
}
public class TestComparerByCount : IComparer<Test>
{
public int Compare(Test x, Test y)
{
if (x.Count > y.Count) return 1;
else if (x.Count < y.Count) return -1;
else return 0;
}
}
And use it in code like this:
var arr = new Test[] { a3, a2, a1 };
Array.Sort(arr, new TestComparerBySum());
Array.Sort(arr, new TestComparerByCount());
I have a list of IDs that represent different things. I want to display these IDs as strings.
For example the number 12 would map to "foo", and 13 would map to "bar"
more specifically i'm attempting to migrate the model properties to a list with the transformed string values. Here is what I have currently
var model = new PaymentExclusionModel
{
ExclusionList = response.Exclusions,
};
List<PaymentProcessorExclusionModel> list = new List<PaymentProcessorExclusionModel>();
list = response.Exclusions.Select(x => new PaymentProcessorExclusionModel
{
// Convert
});
I know what values to map the integers to strings, since it's a small set of values. I have attempted to use a Dictionary<int, string> but I get an error complaining about converting an int? to int (int? is from metadata dll and I can't change that).
Here is the code:
var model = new PaymentExclusionModel
{
ExclusionList = response.Exclusions,
};
List<PaymentProcessorExclusionModel> list = new List<PaymentProcessorExclusionModel>();
list = response.Exclusions.Select(x => new PaymentProcessorExclusionModel
{
PaymentType = dict[x.PaymentTypeId.Value]
});
Error Code:
Error CS0266 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<DK.Fin.Secure.Mjolnir.Web.Models.PaymentProcessorExclusionModel>' to 'System.Collections.Generic.List<Web.Models.PaymentProcessorExclusionModel>'. An explicit conversion exists (are you missing a cast?)
Here is an enum-style solution:
public class MyType : EnumClass
{
public static MyType FOO = new MyType(12, "Foo");
public static MyType BAR = new MyType(13, "Bar");
public static MyType X = new MyType(99, "X");
[JsonConstructor]
private MyType(int id, string name)
{
_id = id;
_name = name;
}
public static MyType GetMyType(int id)
{
switch (id)
{
case 12: return FOO;
case 13: return BAR;
case 99: return X;
default: return null;
}
}
public static IEnumerable<MyType> GetMyTypes()
{
return new List<MyType>
{
FOO,
BAR,
X
};
}
}
I've used this type of thing with GREAT success. I had a poker app and in that case the 'MyType' was 'Card' with all of the attributes of a playing card (suit, number, etc).
The EnumClass
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyProj.MyPath
{
public abstract class EnumClass
{
protected int _id;
protected string _name;
public virtual int ID
{
get { return _id; }
}
public virtual string Name
{
get { return _name; }
}
public override string ToString()
{
return Name;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is EnumClass)
return ID == (obj as EnumClass).ID;
return base.Equals(obj);
}
public static bool operator ==(EnumClass left, EnumClass right)
{
if ((left as Object) == null)
return (right as Object) == null;
return left.Equals(right);
}
public static bool operator !=(EnumClass left, EnumClass right)
{
if ((left as Object) == null)
return (right as Object) != null;
return !left.Equals(right);
}
}
}
I don't really get why but i believe you want to create an array map between string and int values.
First you would want to use a dictionary
Dictionary<int, string> map = new Dictionary<int, string>();
Then simply add your values
map.Add(12, 'foo');
map.Add(13, 'bar');
Then basically all you have to do is call the dictionary like an array
list = response.Exclusions.Select(x => new PaymentProcessorExclusionModel
{
NewId = map.ContainsKey(x) ? map[x] : "defaultkey?"
});
This is obviously the way to go. Try creating your 'list' variable dynamically like so
var list = response.Exclusions.Select(x => new PaymentProcessorExclusionModel
{
PaymentType = dict[x.PaymentTypeId.Value]
});
I'm trying to solve a Leetcode problem Binary Tree Preorder Traversal. Below is what I wrote so far :
using System.Collections.Generic;
using System.Linq;
public class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) { val = x; }
}
public class Solution
{
public IList<int> PreorderTraversal(TreeNode root)
{
if (root == null)
{
return new List<int> { };
}
else
{
IList<int> ret = new List<int> { root.val };
ret = ret.Concat(PreorderTraversal(root.left)) as IList<int>;
ret = ret.Concat(PreorderTraversal(root.right)) as IList<int>;// <-- this line
return ret;
}
}
}
class Program
{
static void Main(string[] args)
{
var root = new TreeNode(42);
root.right = new TreeNode(99);
var result = new Solution().PreorderTraversal(root);
}
}
I tried the same algorithm with ToList(), it worked. But when running this code, System.ArgumentNullException was thrown at the line I marked. So my question is where did it come from? How to understand it? How to fix it?
Although your initial value for ret is an IList<int>, the return type when using .Concat is an IEnumerable<int>. However you use a safe (as) cast back to an IList<Int>; that's not a valid cast and so your first .Concat operation returns null... The next line then tries to operate on a null value.
.Concat is implemented as an extension method that takes the source (ret in this case) as an argument so it throws an ArgumentNullException when null is passed.
You could fix this by using IEnumerable<int> as the return type and for the declaration of ret and removing your casts.
using System.Collections.Generic;
using System.Linq;
public class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) { val = x; }
}
public class Solution
{
public IEnumerable<int> PreorderTraversal(TreeNode root)
{
if (root == null)
{
return Enumerable.Empty<int>();
}
else
{
IEnumerable<int> ret = new List<int> { root.val };
ret = ret.Concat(PreorderTraversal(root.left));
ret = ret.Concat(PreorderTraversal(root.right));
return ret;
}
}
}
class Program
{
static void Main(string[] args)
{
var root = new TreeNode(42);
root.right = new TreeNode(99);
var result = new Solution().PreorderTraversal(root);
}
}
I have two lists, I need to find the items in the first list that are missing from the second, but I can only compare them with a Boolean function.
class A
{
internal bool Matching(A a)
{
return true;
}
}
class OuterMatch
{
List<A> List1 = new List<A>();
List<A> List2 = new List<A>();
void BasicOuterJoin()
{
// textbook example of an outer join, but it does not use my Matching function
var missingFrom2 = from one in List1
join two in List2
on one equals two into matching
from match in matching.DefaultIfEmpty()
where match == null
select one;
}
void Matching()
{
// simple use of the matching function, but this is an inner join.
var matching = from one in List1
from two in List2
where one.Matching(two)
select one;
}
void MissingBasedOnMatching()
{
// a reasonable substitute for what I'm after
var missingFrom2 = from one in List1
where (from two in List2
where two.Matching(one)
select two)
.Count() == 0
select one;
}
MissingBasedOnMatching gives me the right results, but it's not visually obviously an outer join like BasicOuterJoin is. Is there a clearer way to do this?
There's a form of GroupJoin that takes a comparison operator, but I'm not clear if there is a way to use it to make an outer join.
I've been using some useful (and short!) code from a blog by Ed Khoze.
He's posted a handy class which provides an adapter so that you can use Enumerable.Except() with a lambda.
Once you have that code, you can use Except() to solve your problem like so:
var missing = list1.Except(list2, (a, b) => a.Matching(b));
Here's a complete compilable sample. Credit to Ed Khoze for the LINQHelper class:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class A
{
public int Value;
public bool Matching(A a)
{
return a.Value == Value;
}
public override string ToString()
{
return Value.ToString();
}
}
class Program
{
void test()
{
var list1 = new List<A>();
var list2 = new List<A>();
for (int i = 0; i < 20; ++i) list1.Add(new A {Value = i});
for (int i = 4; i < 16; ++i) list2.Add(new A {Value = i});
var missing = list1.Except(list2, (a, b) => a.Matching(b));
missing.Print(); // Prints 0 1 2 3 16 17 18 19
}
static void Main()
{
new Program().test();
}
}
static class MyEnumerableExt
{
public static void Print<T>(this IEnumerable<T> sequence)
{
foreach (var item in sequence)
Console.WriteLine(item);
}
}
public static class LINQHelper
{
private class LambdaComparer<T>: IEqualityComparer<T>
{
private readonly Func<T, T, bool> _lambdaComparer;
private readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 0)
{
}
private LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaComparer = lambdaComparer;
_lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}
public static IEnumerable<TSource> Except<TSource>
(
this IEnumerable<TSource> enumerable,
IEnumerable<TSource> second,
Func<TSource, TSource, bool> comparer
)
{
return enumerable.Except(second, new LambdaComparer<TSource>(comparer));
}
}
}
If your problem statement is actually
Find all members of X that do not exist in Y
And given a class Foo that implements IEquatable<Foo> (pretty much what your Matching method does):
class Foo : IEquatable<Foo>
{
public bool Equals( Foo other )
{
throw new NotImplementedException();
}
}
Then this code should give you what you want:
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
List<Foo> xNotInY = x.Where( xItem => ! y.Any( yItem => xItem.Equals(yItem) ) ).ToList() ;
You should bear in mind that this runs in O(N2) time. Consequently, you might want to implement an IEqualityComparer<Foo> and put your second list in a HashSet<Foo>:
class FooComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if ( x == null )
{
return y == null ;
}
else if ( y == null ) return false ;
else
{
return x.Equals(y) ;
}
}
public int GetHashCode(Foo obj)
{
return obj.GetHashCode() ;
}
}
Then do something like
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
HashSet<Foo> yLookup = new HashSet<Foo>( y , new FooComparer() ) ;
List<Foo> xNotInY = x.Where( x => !yLookup.Contains(x) ) ;
You'll incur some overhead in constructing the hash set (1 pass through the second list), but subsequent lookups via Contains() are O(1).
If you look at the sources for the Linq join operation, this is close to what it does.
It wouldn't be difficult to strip the Linq sources for Join() and it's helpers and tweak them to product left and right join operators instead of the stock inner join.
Does this work for your purposes?
var missing = List1.Except(List2);
If you need custom comparison logic you can build a custom IEqualityComparer. Note however that Except treats both lists as sets, so it will eliminate duplicates from List1.