2

プロパティのセットを持つクラス Product があります。

public class Product
{
     public string Id { get; set; }
     public string Name { get; set; }
     public string Categories { get; set; }
}

コンポーネントから を取得し、List<Product>いくつかの理由から、Reflectionを使用して のプロパティを取得Productし、各プロパティのDistinct値とその値を 取得する必要がありCount()ます。

振り返りによって目標を達成することは可能ですか? そうでない場合、それを行う他の方法はありますか?ありがとう!

アップデート

問題は、どのプロパティを使用する必要があり、どのプロパティがProductクラスに含まれているかを事前に知らないことです。だからこそ、リフレクションが最良の選択肢だと思います。

Switch - Caseスイッチがクラスから抽出されたProperty NameCaseを比較し、それぞれが特定のProperty Nameに対応する構造を使用して、同じ結果を得ることができます。しかし、このソリューションの柔軟性は私の問題には十分ではありません

4

6 に答える 6

4
private static int DistinctCount<T>(IEnumerable<T> items, string property)
{
    var propertyInfo = typeof(T).GetProperty(property);

    return items.Select(x => propertyInfo.GetValue(x, null)).Distinct().Count();
}

使用法:

List<Product> prods = GetProductsFromSomeplace();

int distinctCountById = DistinctCount(prods, "Id");
int distinctCountByName = DistinctCount(prods, "Name");
int distinctCountByCategories = DistinctCount(prods, "Categories");

プロパティのカスタムIEqualityComparerを許可する場合は、オーバーロードを設定できます。

private static int DistinctCount<TItems, TProperty>(IEnumerable<TItems> items,
                                                    string property,
                                                    IEqualityComparer<TProperty> propertyComparer)
{
    var propertyInfo = typeof(TItems).GetProperty(property);

    return items.Select(x => (TProperty)propertyInfo.GetValue(x, null))
                                 .Distinct(propertyComparer).Count();
}

そして、そのように使用します:

List<Product> prods = GetProductsFromSomeplace();

int distinctCountById = DistinctCount(prods, "Id", new MyCustomIdComparer());

MyCustomIdComparerが実装する場所IEqualityComparer<TProperty>(この場合IEC<int>

于 2012-05-02T15:48:12.163 に答える
4

つまり、私たちが以前考えていたものとは少し異なるものを求めているように思えます。個別の値の数を探していないか、各個別の値の重複の数を探しています。これは、基本的に各グループのカウントを持つグループ化です。

private static Dictionary<string, Dictionary<object, int>> 
    getDistinctValues<T>(List<T> list)
{
    var properties = typeof(T).GetProperties();

    var result = properties
        //The key of the first dictionary is the property name
        .ToDictionary(prop => prop.Name,
            //the value is another dictionary
            prop => list.GroupBy(item => prop.GetValue(item, null))
                //The key of the inner dictionary is the unique property value
                //the value if the inner dictionary is the count of that group.
                .ToDictionary(group => group.Key, group => group.Count()));

    return result;
}

ある時点でこれを 2 つの方法に分割しましたが、必要ないと思われるところまで少し圧縮しました。このクエリのネストのすべてのレベルに頭を悩ませている場合は、お気軽にさらに説明を求めてください。

于 2012-05-02T15:42:08.487 に答える
0

さて、私は私の答えで少し実行されましたが、これは...本格的な個別の値カウンターです。これはあなたの質問に完全に答えるものではありませんが、特定のオブジェクトのプロパティをカウントするための良い出発点になるはずです。これを使用して、オブジェクトのすべてのプロパティをループすることと組み合わせて、トリックを行う必要があります:p

/// <summary>
/// A distinct value counter, using reflection
/// </summary>
public class DistinctValueCounter<TListItem>
{
    /// <summary>
    /// Gets or sets the associated list items
    /// </summary>
    private IEnumerable<TListItem> ListItems { get; set; }

    /// <summary>
    /// Constructs a new distinct value counter
    /// </summary>
    /// <param name="listItems">The list items to check</param>
    public DistinctValueCounter(IEnumerable<TListItem> listItems)
    {
        this.ListItems = listItems;
    }

    /// <summary>
    /// Gets the distinct values, and their counts
    /// </summary>
    /// <typeparam name="TProperty">The type of the property expected</typeparam>
    /// <param name="propertyName">The property name</param>
    /// <returns>A dictionary containing the distinct counts, and their count</returns>
    public Dictionary<TProperty, int> GetDistinctCounts<TProperty>(string propertyName)
    {
        var result = new Dictionary<TProperty, int>();

        // check if there are any list items
        if (this.ListItems.Count() == 0)
        {
            return result;
        }

        // get the property info, and check it exists
        var propertyInfo = this.GetPropertyInfo<TProperty>(this.ListItems.FirstOrDefault(), propertyName);
        if (propertyInfo == null)
        {
            return result;
        }

        // get the values for the property, from the list of items
        return ListItems.Select(item => (TProperty)propertyInfo.GetValue(item, null))
            .GroupBy(value => value)
            .ToDictionary(value => value.Key, value => value.Count());
    }

    /// <summary>
    /// Gets the property information, for a list item, by its property name
    /// </summary>
    /// <typeparam name="TProperty">The expected property type</typeparam>
    /// <param name="listItem">The list item</param>
    /// <param name="propertyName">The property name</param>
    /// <returns>The property information</returns>
    private PropertyInfo GetPropertyInfo<TProperty>(TListItem listItem, string propertyName)
    {
        // if the list item is null, return null
        if (listItem == null)
        {
            return null;
        }

        // get the property information, and check it exits
        var propertyInfo = listItem.GetType().GetProperty(propertyName);
        if (propertyInfo == null)
        {
            return null;
        }

        // return the property info, if it is a match
        return propertyInfo.PropertyType == typeof(TProperty) ? propertyInfo : null;
    }
}

使用法:

var counter = new DistinctValueCounter<Person>(people);
var resultOne = counter.GetDistinctCounts<string>("Name");
于 2012-05-02T16:10:53.817 に答える
0

リストが型付けされていないProductが、実際にはオープン ジェネリック パラメーターTを使用しており、このパラメーターに制限がない場合 ( where T : Product)、キャストが役立ちます。

int count = list
    .Cast<Product>()
    .Select(p => p.Id)
    .Distinct()
    .Count();  
于 2012-05-02T15:50:20.593 に答える
-1

目標を理解していれば、LINQ を使用できるはずです。

List<Product> products = /* whatever */
var distinctIds = products.Select(p=>p.Id).Distinct();
var idCount = distinctIds.Count();
...
于 2012-05-02T15:41:50.567 に答える