বস্তুগুলিতে ল্যাম্বদা / লিনক ব্যবহার করে একটি তালিকা বাছাই করা


274

আমার কাছে স্ট্রিংয়ের মাধ্যমে "সম্পত্তি অনুসারে বাছাই করা" নাম রয়েছে। অবজেক্টের তালিকাটি সাজানোর জন্য আমার ল্যাম্বদা / লিনক ব্যবহার করতে হবে।

উদা:

public class Employee
{
  public string FirstName {set; get;}
  public string LastName {set; get;}
  public DateTime DOB {set; get;}
}


public void Sort(ref List<Employee> list, string sortBy, string sortDirection)
{
  //Example data:
  //sortBy = "FirstName"
  //sortDirection = "ASC" or "DESC"

  if (sortBy == "FirstName")
  {
    list = list.OrderBy(x => x.FirstName).toList();    
  }

}
  1. ক্ষেত্রের নাম (সাজ্টবাই) যাচাই করার জন্য গুচ্ছ ifs ব্যবহার করার পরিবর্তে, বাছাই করার একটি পরিষ্কার উপায় আছে কি?
  2. বাছাই ডেটাটাইপ সম্পর্কে সচেতন?


আমি সাজ্টবাই == "প্রথম নাম" দেখছি । ওপি বলতে কি বোঝায় ? পরিবর্তে () বিকল্পগুলি () ?
পিটার

3
@ পিটার তিনি সম্ভবত সমতার তুলনা করতে চেয়েছিলেন, তবে আমি সন্দেহ করি যে তিনি "করতে চেয়েছিলেন। সমীকরণ ()"। টাইপোর সাধারণত কোডের ফলাফল হয় না যা কার্য করে।
সি। এভেনহুইস

1
@ পিটার আপনার প্রশ্নটি তখনই বোধগম্য হয় যদি আপনি মনে করেন যে এতে কিছু ভুল আছে ==... কী?
জিম বাল্টার

উত্তর:


365

এটি হিসাবে করা যেতে পারে

list.Sort( (emp1,emp2)=>emp1.FirstName.CompareTo(emp2.FirstName) );

.NET ফ্রেমওয়ার্কটি ল্যাম্বডাকে (emp1,emp2)=>intএকটি হিসাবে কাস্ট করছেComparer<Employee>.

দৃ strongly়ভাবে টাইপ করার সুবিধা রয়েছে।


এন্টিসিমেট্রি নিশ্চিত করার জন্য একাধিক তুলনার মানদণ্ড এবং শেষ পর্যন্ত একটি ব্যর্থ সাফ গিউডি তুলনা জড়িত জটিল তুলনা অপারেটরগুলি লিখতে আমার প্রায়শই ঘটেছিল। এর মতো জটিল তুলনার জন্য আপনি কি ল্যাম্বডা এক্সপ্রেশন ব্যবহার করবেন? যদি তা না হয় তবে এর অর্থ কি ল্যাম্বডা এক্সপ্রেশন তুলনা কেবল সাধারণ ক্ষেত্রে সীমাবদ্ধ হওয়া উচিত?
সিমোন

4
হ্যাঁ, আমি কি এটি দেখতে এরকম কিছু দেখছি না? list.Sort ((emp1, emp2) => emp1.GetType ()। getProperty (sortBy) .GetValue (emp1, নাল) .কম্পেটটো (এমপ 2.গেটটাইপ ()। getProperty (সাজ্টবাই)। গেটভ্যালু (এমপ 2, নাল))) ;
শনিবার

1
বিপরীতে সাজানোর কিভাবে?
জেরিওয়েল

1
@ জেরিগোয়েল প্যারামগুলি অদলবদল করুন ... এমপ 2. ফার্স্টনাম.কম্পেরটো (এমপ 1. ফার্স্টনাম) ইত্যাদি
ক্রিস হাইনেস

3
এটি কারণ একটি ফাংশন রেফারেন্স এটি একটি একলাইনার হতে হবে না। আপনি কেবল লিখতে পারেনlist.sort(functionDeclaredElsewhere)
দ্য হাফ

74

একটি জিনিস আপনি যা করতে পারেন তা হ'ল Sortএটি ল্যাম্বডাসের আরও ভাল ব্যবহার করে।

public enum SortDirection { Ascending, Descending }
public void Sort<TKey>(ref List<Employee> list,
                       Func<Employee, TKey> sorter, SortDirection direction)
{
  if (direction == SortDirection.Ascending)
    list = list.OrderBy(sorter);
  else
    list = list.OrderByDescending(sorter);
}

Sortপদ্ধতিটি কল করার সময় আপনি বাছাই করতে ক্ষেত্রটি নির্দিষ্ট করতে পারেন ।

Sort(ref employees, e => e.DOB, SortDirection.Descending);

7
সাজানোর কলামটি যেহেতু স্ট্রিংয়ে রয়েছে তাই কোন ফাংশনটি এটি পাস করবে তা নির্ধারণ করতে আপনার এখনও একটি স্যুইচ / যদি-অন্য ব্লক প্রয়োজন need
tvanfosson

1
আপনি এই অনুমান করতে পারবেন না। কে জানে তার কোড এটি কল করে।
স্যামুয়েল 19

3
তিনি প্রশ্নে বলেছিলেন যে "সম্পত্তি অনুসারে বাছাই করা" একটি স্ট্রিংয়ে রয়েছে। আমি শুধু তার প্রশ্নে যাচ্ছি।
tvanfosson

6
আমি মনে করি এটি সম্ভবত বেশি কারণ এটি কোনও ওয়েব পৃষ্ঠায় বাছাই করা নিয়ন্ত্রণ থেকে আসে যা সারণি কলামটি স্ট্রিং প্যারামিটার হিসাবে ফিরে আসে। যাইহোক, এটি আমার ব্যবহারের কেস হবে।
tvanfosson

2
@ ট্যাননফসন - আপনি ঠিক বলেছেন, আমার একটি কাস্টম নিয়ন্ত্রণ রয়েছে যার একটি স্ট্রিং হিসাবে ক্রম এবং ক্ষেত্রের নাম রয়েছে
ডটনেটডুড

55

সম্পত্তির মান পেতে আপনি প্রতিবিম্ব ব্যবহার করতে পারেন।

list = list.OrderBy( x => TypeHelper.GetPropertyValue( x, sortBy ) )
           .ToList();

যেখানে টাইপহেল্পারের স্থির পদ্ধতি রয়েছে যেমন:

public static class TypeHelper
{
    public static object GetPropertyValue( object obj, string name )
    {
        return obj == null ? null : obj.GetType()
                                       .GetProperty( name )
                                       .GetValue( obj, null );
    }
}

আপনি ভিএস ২০০৮ নমুনাগুলি লাইব্রেরি থেকে ডায়নামিক লিনকিউতেও দেখতে চাইতে পারেন । আপনি আইকিউয়েরেবল হিসাবে তালিকাটি কাস্ট করতে আইনিউমারেবল এক্সটেনশন ব্যবহার করতে পারেন এবং তারপরে ডায়নামিক লিঙ্ক অর্ডারবাই এক্সটেনশনটি ব্যবহার করতে পারেন।

 list = list.AsQueryable().OrderBy( sortBy + " " + sortDirection );

1
যদিও এটি তার সমস্যার সমাধান করে, আমরা সম্ভবত এটি বাছাইয়ের জন্য স্ট্রিং ব্যবহার করা থেকে দূরে রাখতে চাই। ভাল উত্তর-কম-না।
স্যামুয়েল 19

তার প্রয়োজন অনুসারে লিনক থেকে এসকিএল ব্যতীত আপনি ডায়নামিক লিনাক ব্যবহার করতে পারেন ... আমি এটি পছন্দ করি
জোশবার্ক

অবশ্যই। আপনি এটিকে আইকোয়্যারেবলে রূপান্তর করতে পারেন। এ নিয়ে ভাবিনি। আমার উত্তর আপডেট করা হচ্ছে।
tvanfosson

@ সামুয়েল যদি বাছাইয়ের রুট ভেরিয়েবল হিসাবে চলে আসে তবে এটিকে বাছাই করার কোনও উপায় নেই।
শেভ

1
@ চকড - সংগ্রহটি ব্যবহারের চেষ্টা করার আগে স্মৃতিতে collection.ToList().OrderBy(x => TypeHelper.GetPropertyValue( x, sortBy)).ToList();
আনুন

20

এইভাবে আমি আমার সমস্যার সমাধান করেছি:

List<User> list = GetAllUsers();  //Private Method

if (!sortAscending)
{
    list = list
           .OrderBy(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
           .ToList();
}
else
{
    list = list
           .OrderByDescending(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
           .ToList();
}

16

অর্ডারটি এক্সপ্রেশন দিয়ে বিল্ডিং এখানে পড়তে পারেন

লিঙ্কে পৃষ্ঠা থেকে নির্লজ্জভাবে চুরি:

// First we define the parameter that we are going to use
// in our OrderBy clause. This is the same as "(person =>"
// in the example above.
var param = Expression.Parameter(typeof(Person), "person");

// Now we'll make our lambda function that returns the
// "DateOfBirth" property by it's name.
var mySortExpression = Expression.Lambda<Func<Person, object>>(Expression.Property(param, "DateOfBirth"), param);

// Now I can sort my people list.
Person[] sortedPeople = people.OrderBy(mySortExpression).ToArray();

এর সাথে সম্পর্কিত সমস্যাগুলি রয়েছে: ডেটটাইম বাছাই।
ক্রেজিইনিগমা

এছাড়াও কম্পোজিট ক্লাস, অর্থাৎ পার্সোন.এম্পপ্লায়ার.কম্প্যানি নাম সম্পর্কে কীভাবে?
davewilliams459

আমি মূলত একই জিনিসটি করছিলাম এবং এই উত্তরটি এটি সমাধান করেছে।
জেসন.নেট

8

সম্পত্তিটি অ্যাক্সেস করতে আপনি প্রতিবিম্বটি ব্যবহার করতে পারেন।

public List<Employee> Sort(List<Employee> list, String sortBy, String sortDirection)
{
   PropertyInfo property = list.GetType().GetGenericArguments()[0].
                                GetType().GetProperty(sortBy);

   if (sortDirection == "ASC")
   {
      return list.OrderBy(e => property.GetValue(e, null));
   }
   if (sortDirection == "DESC")
   {
      return list.OrderByDescending(e => property.GetValue(e, null));
   }
   else
   {
      throw new ArgumentOutOfRangeException();
   }
}

মন্তব্য

  1. আপনি কেন রেফারেন্স দিয়ে তালিকাটি পাস করবেন?
  2. সাজানোর দিকনির্দেশের জন্য আপনার একটি এনাম ব্যবহার করা উচিত।
  3. আপনি যদি কোনও ল্যাম্বডা এক্সপ্রেশনটি পাস করেন তবে সম্পত্তিটির নামের পরিবর্তে স্ট্রিং হিসাবে নামটি সাজানোর জন্য সম্পত্তিটি নির্দিষ্ট করে এমন আপনি একটি ক্লিনার সমাধান পেতে পারেন।
  4. আমার উদাহরণের তালিকায় == নাল একটি নাল রেফারেন্সেক্সেক্সেশন সৃষ্টি করবে, আপনার এই কেসটি ধরা উচিত।

অন্য কেউ কি কখনও খেয়াল করেছেন যে এটি একটি রিটার্ন টাইপের শূন্যতা কিন্তু তালিকাগুলি ফেরত দেয়?
এমডি

কমপক্ষে কেউ এটিকে ঠিক করার জন্য যত্ন নেন নি এবং আমি এটি লক্ষ্য করিনি কারণ আমি কোনও আইডিই ব্যবহার করে কোডটি লিখিনি। যে ইশারা জন্য ধন্যবাদ।
ড্যানিয়েল ব্রুকনার

6

বাছাইটি IComparable ইন্টারফেস ব্যবহার করে, যদি টাইপটি এটি প্রয়োগ করে। এবং আপনি কাস্টম আইসিএমপিয়ার প্রয়োগ করে আইএফএস এড়াতে পারবেন:

class EmpComp : IComparer<Employee>
{
    string fieldName;
    public EmpComp(string fieldName)
    {
        this.fieldName = fieldName;
    }

    public int Compare(Employee x, Employee y)
    {
        // compare x.fieldName and y.fieldName
    }
}

এবং তারপর

list.Sort(new EmpComp(sortBy));

এফওয়াইআই: বাছাই হল তালিকার <টি> এর একটি পদ্ধতি এবং লিনক এক্সটেনশন নয়।
সের্গেই

5

1 এর জন্য উত্তর .:

স্ট্রিং হিসাবে নামটি ব্যবহার করে ম্যানুয়ালি একটি এক্সপ্রেশন ট্রি তৈরি করতে সক্ষম হওয়া উচিত যা অর্ডারবাইতে যেতে পারে। অথবা আপনি অন্য উত্তরের পরামর্শ অনুসারে প্রতিবিম্ব ব্যবহার করতে পারেন, যা কম কাজ হতে পারে।

সম্পাদনা করুন : ম্যানুয়ালি একটি এক্সপ্রেশন ট্রি তৈরির একটি কার্যকারী উদাহরণ। (এক্স.ভ্যালুতে বাছাই করা, যখন কেবলমাত্র সম্পত্তির "মান" নাম জেনে)। এটি করার জন্য আপনি একটি জেনেরিক পদ্ধতি তৈরি করতে পারেন (উচিত)।

using System;
using System.Linq;
using System.Linq.Expressions;

class Program
{
    private static readonly Random rand = new Random();
    static void Main(string[] args)
    {
        var randX = from n in Enumerable.Range(0, 100)
                    select new X { Value = rand.Next(1000) };

        ParameterExpression pe = Expression.Parameter(typeof(X), "value");
        var expression = Expression.Property(pe, "Value");
        var exp = Expression.Lambda<Func<X, int>>(expression, pe).Compile();

        foreach (var n in randX.OrderBy(exp))
            Console.WriteLine(n.Value);
    }

    public class X
    {
        public int Value { get; set; }
    }
}

এক্সপ্রেশন ট্রি তৈরির জন্য আপনার অবশ্যই পার্টিকপটিংয়ের প্রকারগুলি জানতে হবে। এটি আপনার ব্যবহারের দৃশ্যে সমস্যা হতে পারে বা নাও হতে পারে। কী ধরণের বাছাই করা উচিত তা যদি আপনি না জানেন তবে প্রতিবিম্বটি ব্যবহার করে এটি সহজতর হবে।

2 এর জন্য উত্তর .:

হ্যাঁ, তুলনা করার পরে <T>। ডিফল্টটি তুলনা করার জন্য ব্যবহৃত হবে, যদি আপনি স্পষ্টভাবে তুলনাকারীকে সংজ্ঞায়িত না করেন।


আপনার কাছে অর্ডারবাইতে যাওয়ার জন্য একটি অভিব্যক্তি গাছ তৈরির উদাহরণ রয়েছে?
ডটনেটডুড

4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;

public static class EnumerableHelper
{

    static MethodInfo orderBy = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "OrderBy" && x.GetParameters().Length == 2).First();

    public static IEnumerable<TSource> OrderBy<TSource>(this IEnumerable<TSource> source, string propertyName)
    {
        var pi = typeof(TSource).GetProperty(propertyName, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
        var selectorParam = Expression.Parameter(typeof(TSource), "keySelector");
        var sourceParam = Expression.Parameter(typeof(IEnumerable<TSource>), "source");
        return 
            Expression.Lambda<Func<IEnumerable<TSource>, IOrderedEnumerable<TSource>>>
            (
                Expression.Call
                (
                    orderBy.MakeGenericMethod(typeof(TSource), pi.PropertyType), 
                    sourceParam, 
                    Expression.Lambda
                    (
                        typeof(Func<,>).MakeGenericType(typeof(TSource), pi.PropertyType), 
                        Expression.Property(selectorParam, pi), 
                        selectorParam
                    )
                ), 
                sourceParam
            )
            .Compile()(source);
    }

    public static IEnumerable<TSource> OrderBy<TSource>(this IEnumerable<TSource> source, string propertyName, bool ascending)
    {
        return ascending ? source.OrderBy(propertyName) : source.OrderBy(propertyName).Reverse();
    }

}

আর একটি, এই মুহুর্তে কোনও আইকিউয়েরেবলের জন্য:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class IQueryableHelper
{

    static MethodInfo orderBy = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "OrderBy" && x.GetParameters().Length == 2).First();
    static MethodInfo orderByDescending = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "OrderByDescending" && x.GetParameters().Length == 2).First();

    public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, params string[] sortDescriptors)
    {
        return sortDescriptors.Length > 0 ? source.OrderBy(sortDescriptors, 0) : source;
    }

    static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string[] sortDescriptors, int index)
    {
        if (index < sortDescriptors.Length - 1) source = source.OrderBy(sortDescriptors, index + 1);
        string[] splitted = sortDescriptors[index].Split(' ');
        var pi = typeof(TSource).GetProperty(splitted[0], BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.IgnoreCase);
        var selectorParam = Expression.Parameter(typeof(TSource), "keySelector");
        return source.Provider.CreateQuery<TSource>(Expression.Call((splitted.Length > 1 && string.Compare(splitted[1], "desc", StringComparison.Ordinal) == 0 ? orderByDescending : orderBy).MakeGenericMethod(typeof(TSource), pi.PropertyType), source.Expression, Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(TSource), pi.PropertyType), Expression.Property(selectorParam, pi), selectorParam)));
    }

}

আপনি একাধিক বাছাইয়ের মাপদণ্ড এটি পাস করতে পারেন:

var q = dc.Felhasznalos.OrderBy(new string[] { "Email", "FelhasznaloID desc" });

4

রাশাকের সরবরাহিত সমাধানটি দুর্ভাগ্যক্রমে মান ধরণের (ইন্ট, এনাম ইত্যাদি) কাজ করে না।

এটি যে কোনও ধরণের সম্পত্তি নিয়ে কাজ করার জন্য, আমি এটিই পেয়েছি এমন সমাধান:

public static Expression<Func<T, object>> GetLambdaExpressionFor<T>(this string sortColumn)
    {
        var type = typeof(T);
        var parameterExpression = Expression.Parameter(type, "x");
        var body = Expression.PropertyOrField(parameterExpression, sortColumn);
        var convertedBody = Expression.MakeUnary(ExpressionType.Convert, body, typeof(object));

        var expression = Expression.Lambda<Func<T, object>>(convertedBody, new[] { parameterExpression });

        return expression;
    }

এটি দুর্দান্ত এবং এমনকি সঠিকভাবে এসকিউএল অনুবাদ করা হয়!
জাভিয়ের পইনাস

1

@ সামুয়েল এবং @ ব্লুশ কী করেছে তাতে যুক্ত হচ্ছে। এটি অনেক খাটো কারণ এনাম এ ক্ষেত্রে অপ্রয়োজনীয় ছিল। অতিরিক্ত বোনাস হিসাবে যখন অ্যাসেন্ডিংটি পছন্দসই ফলাফল হয়, আপনি তৃতীয় প্যারামিটারের ডিফল্ট উত্তর হওয়ায় আপনি 3 এর পরিবর্তে মাত্র 2 পরামিতি পাস করতে পারেন।

public void Sort<TKey>(ref List<Person> list, Func<Person, TKey> sorter, bool isAscending = true)
{
    list = isAscending ? list.OrderBy(sorter) : list.OrderByDescending(sorter);
}

0

যদি আপনি কলামের নাম এবং সার্ট হিসাবে দিকটি সাজান এবং স্ট্রিং হিসাবে স্যুইচটি ব্যবহার করতে না চান বা অন্য কোনও বাক্য গঠন কলাম নির্ধারণ করতে চান তবে এই উদাহরণটি আপনার জন্য আকর্ষণীয় হতে পারে:

private readonly Dictionary<string, Expression<Func<IuInternetUsers, object>>> _sortColumns = 
        new Dictionary<string, Expression<Func<IuInternetUsers, object>>>()
    {
        { nameof(ContactSearchItem.Id),             c => c.Id },
        { nameof(ContactSearchItem.FirstName),      c => c.FirstName },
        { nameof(ContactSearchItem.LastName),       c => c.LastName },
        { nameof(ContactSearchItem.Organization),   c => c.Company.Company },
        { nameof(ContactSearchItem.CustomerCode),   c => c.Company.Code },
        { nameof(ContactSearchItem.Country),        c => c.CountryNavigation.Code },
        { nameof(ContactSearchItem.City),           c => c.City },
        { nameof(ContactSearchItem.ModifiedDate),   c => c.ModifiedDate },
    };

    private IQueryable<IuInternetUsers> SetUpSort(IQueryable<IuInternetUsers> contacts, string sort, string sortDir)
    {
        if (string.IsNullOrEmpty(sort))
        {
            sort = nameof(ContactSearchItem.Id);
        }

        _sortColumns.TryGetValue(sort, out var sortColumn);
        if (sortColumn == null)
        {
            sortColumn = c => c.Id;
        }

        if (string.IsNullOrEmpty(sortDir) || sortDir == SortDirections.AscendingSort)
        {
            contacts = contacts.OrderBy(sortColumn);
        }
        else
        {
            contacts = contacts.OrderByDescending(sortColumn);
        }

        return contacts;
    }

এক্সপ্রেশন> এবং এর কী স্ট্রিংয়ের মাধ্যমে সাজানোর কলামের জন্য প্রয়োজনীয় সংযোগ স্থাপন করে এমন অভিধান ব্যবহারের ভিত্তিতে সমাধান।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.