Func< TElement,TKey1,TKey2>致IComparer< TElement>? [英] Func<TElement, TKey1, TKey2> To IComparer<TElement>?

查看:103
本文介绍了Func< TElement,TKey1,TKey2>致IComparer< TElement>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述





我设法使用这个doohickey [ ^ ]转换Func< TElement,TKey>进入IComparer< telement>。我现在可以创建一个SortedList:

Hi,

I have managed to use this doohickey [^] to convert a Func<TElement, TKey> into a IComparer<telement>. I can now create a SortedList as so:

public OrderedQueue(Func<T, IComparable> orderByFunc, bool @descending = false )
{
  Queue = new SortedSet<T>(orderByFunc.ToComparer());
}

....
new OrderedQueue<WorkflowDataAccess.Projections.Message>(m => m.Due);



(是的,我还在使用通用的有序队列)



现在我想要更多。我希望能够传递如下多种功能:


(yes, I am still playing with a generic Ordered Queue)

now I want more. I want to be able to pass in multiple functions as below:

new OrderedQueue<WorkflowDataAccess.Projections.Message>(m=>m.Urgency, m => m.Due);







所以我想我会有第一个func.ToComparer,然后是另一个可以添加该功能的IComparer上的扩展。这就是我被困住的地方。



也许我会以错误的方式去做,或者有更简单的方法来做到这一点,但我有时间去玩^ _ ^



这是我的扩展对象,包括我上面链接的doohickey:




So I figured I would have the first func.ToComparer and then another extension that on that IComparer that could then add the function. This is where I am stuck.

Maybe I'm going about it the wrong way, or there is an easier way to do this, but I have some time to play ^_^

Here are my extension objects including the doohickey I linked above:

public static class FuncExtensions
{
    public static IComparer<TElement> ToComparer<TElement, TKey>(this Func<TElement, TKey> func)
    {
        return  new ProjectionComparer<TElement,TKey>(func);
    }

    public static IComparer<TElement> AddComparison<TElement, TKey>(this IComparer<TElement> comparer,
        Func<TElement, TKey> func)
    {
        //What now?
    }

    internal class ProjectionComparer<TElement, TKey> : IComparer<TElement>
    {
        private readonly Func<TElement, TKey> _keySelector;
        private readonly IComparer<TKey> _comparer;

        internal ProjectionComparer(Func<TElement, TKey> keySelector,
            IComparer<TKey> comparer = null)
        {
            this._keySelector = keySelector;
            this._comparer = comparer ?? Comparer<TKey>.Default;
        }

        public int Compare(TElement x, TElement y)
        {
            TKey keyX = _keySelector(x);
            TKey keyY = _keySelector(y);
            return _comparer.Compare(keyX, keyY);
        }
    }
}

推荐答案

你最容易做的就是板条箱另一个比较器类将连接两个比较器。

The easiest you can do is crate another comparer class that will concatenate the two comparers.
class MultiComparer<TElement> : IComparer<TElement>
{
    private readonly IEnumerable<IComparer<<TElement>> comparers;
    
    public MultiComparer(IEnumerable<IComparer<<TElement>> comparers)
    {
        this.comparers = comparers;
    }
    
    public int Compare(TElement x, TElement y)
    {
        return comparers
            .Select(comparer => comparer.Compare(x, y))
            .FirstOrDefault(result => result <> 0);
    }
}



但也许最好更改ProjectionComparer以支持开箱即用。

我没有通过编译器运行它,但应该足够正确理解。


But maybe it would be better to change ProjectionComparer to support this out of the box.
I didn't run this through the compiler but should be correct enough to understand.


解决方案#1的替代方案可以是可以像这样使用的Comparer:
An alternative to Solution #1 could be a Comparer that can be used like this:
IComparer<DateTime> comparer = ChainedComparer<DateTime>.First(d => d.Year).Then(d => d.Month);



使用以下实现:


With the following implementation:

// Comparer for a prioritized sequence of comparison attributes.
// Implemented as "fluent interface", i.e. usage:
//     ChainedComparer<MyType>.First(v=>v.Prop1).Then(v=>v.Prop2)...Then(v=>v.PropN);
public class ChainedComparer<TValue> : IComparer<TValue>
{
    // sequence of comparison stages: 1st has 1st priority, next has next priority, etc.
    private List<Func<TValue, TValue, int>> _stages;
    // private construction. For named constructor see First(...)
    private ChainedComparer() { _stages = new List<Func<TValue,TValue,int>>(); }
    // named constructor - takes selector for first property for comparison
    public static ChainedComparer<TValue> First<TDimension>(Func<TValue, TDimension> selector)
        where TDimension : IComparable<TDimension>
    {
        return new ChainedComparer<TValue>().Then(selector);
    }
    // selector for next comparison stage
    public ChainedComparer<TValue> Then<TDimension>(Func<TValue, TDimension> selector)
        where TDimension : IComparable<TDimension>
    {
        _stages.Add((a, b) => selector(a).CompareTo(selector(b)));
        return this;
    }
    // implementation of IComparer<T> interface
    public int Compare(TValue a, TValue b)
    {
        return _stages.Select(compare => compare(a, b)).FirstOrDefault(res => res != 0);
    }
}



干杯

Andi


Cheers
Andi


这就是我的意思在审查了Tomas Takac的解决方案1之后提出了





This is what I came up with after reviewing Solution 1 by Tomas Takac


using System;
using System.Collections.Generic;
using System.Linq;

namespace Extensions.Linq
{
    public static class FuncExtensions
    {
        public static IComparer<TElement> ToComparer<TElement,TKey>(this Func<telement,> func) where TKey : IComparable 
        {
            return new ProjectionComparers<TElement,TKey>(func);
        }

        public static IComparer<TElement> ToComparer<TElement,TKey>(this IEnumerable<Func<TElement,TKey>> funcs) where TKey : IComparable 
        {
            return new ProjectionComparers<TElement,TKey>(funcs.ToArray());
        }

        internal class ProjectionComparers<TElement,TKey> : IComparer<TElement> where TKey :IComparable 
        {
            private readonly List<comparedelegate> _compareDelegates = new List<comparedelegate>();

            private delegate int CompareDelegate(TElement x, TElement y);

            internal ProjectionComparers(params Func<TElement,TKey>[] funcs)
            {
                foreach (var f in funcs)
                {
                    var func = f;

                    _compareDelegates.Add(
                        (x, y) =>
                        {
                            TKey keyX = func(x);
                            TKey keyY = func(y);
                            return Comparer<TKey>.Default.Compare(keyX, keyY);
                        });
                }
            }

            //internal ProjectionComparers(params KeyValuePair<Func<TElement,TKey>>,
            //    IComparer<TKey>>[] comparers)
            //{

            //    foreach (var kvp in comparers)
            //    {
            //        var comparer = kvp;

            //        _compareDelegates.Add(
            //            (x, y) =>
            //            {
            //                TKey keyX = comparer.Key(x);
            //                TKey keyY = comparer.Key(y);
            //                return (comparer.Value ?? Comparer<tkey>.Default).Compare(keyX, keyY);
            //            });
            //    }
            //}

            public int Compare(TElement x, TElement y)
            {
                return _compareDelegates
                    .Select(compareDelegate => compareDelegate(x, y))
                    .FirstOrDefault(result => result != 0);
            }
        }
    }
}





尚未测试所以我是我肯定会调整这个解决方案。



编辑:删除了比较器的ctor并坚持认为TKey具有可比性。适合我的情况



Not yet tested so I'm sure I'll be tweaking this solution.

removed the ctor with Comparers and insisted that TKey is comparable. The suits my case fine


这篇关于Func&lt; TElement,TKey1,TKey2&gt;致IComparer&lt; TElement&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆