Сортировать список в списке - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть список продуктов:

public IList<JObject> WhenListProducts()
{
    return new List<JObject>
    {
        JObject.Parse("{ \"gtin\": 1, \"categoryId\": \"cameras\", \"brand\": \"Sony\", \"colour\": \"Blacks\", \"size\": \"Small\", \"quality\": \"Medium\", \"price\": 109.99, \"importance\": 50 }"),
        JObject.Parse("{ \"gtin\": 2, \"categoryId\": \"cameras\", \"brand\": \"Canon\", \"colour\": \"Blacks\", \"size\": \"Large\", \"quality\": \"High\", \"price\": 129.99, \"importance\": 125 }"),
        JObject.Parse("{ \"gtin\": 3, \"categoryId\": \"cameras\", \"brand\": \"Canon\", \"colour\": \"Blacks\", \"size\": \"Small\", \"quality\": \"Medium\", \"price\": 99.99, \"importance\": 75 }"),
        JObject.Parse("{ \"gtin\": 4, \"categoryId\": \"cameras\", \"brand\": \"Nikon\", \"colour\": \"Silvers\", \"size\": \"Large\", \"quality\": \"High\", \"price\": 159.99, \"importance\": 113 }"),
        JObject.Parse("{ \"gtin\": 5, \"categoryId\": \"cameras\", \"brand\": \"Sony\", \"colour\": \"Silvers\", \"size\": \"Small\", \"quality\": \"High\", \"price\": 179.99, \"importance\": 150 }"),
        JObject.Parse("{ \"gtin\": 6, \"categoryId\": \"cameras\", \"brand\": \"Canon\", \"colour\": \"Silvers\", \"size\": \"Large\", \"quality\": \"Low\", \"price\": 116.99, \"importance\": 25 }"),
        JObject.Parse("{ \"gtin\": 7, \"categoryId\": \"cameras\", \"brand\": \"Sony\", \"colour\": \"Blacks\", \"size\": \"Small\", \"quality\": \"High\", \"price\": 189.99, \"importance\": 150 }"),
        JObject.Parse("{ \"gtin\": 8, \"categoryId\": \"cameras\", \"brand\": \"Nikon\", \"colour\": \"Blacks\", \"size\": \"Large\", \"quality\": \"Medium\", \"price\": 129.99, \"importance\": 13 }"),
        JObject.Parse("{ \"gtin\": 9, \"categoryId\": \"cameras\", \"brand\": \"Canon\", \"colour\": \"Reds\", \"size\": \"Small\", \"quality\": \"High\", \"price\": 179.99, \"importance\": 175 }"),
        JObject.Parse("{ \"gtin\": 10, \"categoryId\": \"cameras\", \"brand\": \"Nikon\", \"colour\": \"Silvers\", \"size\": \"Small\", \"quality\": \"High\", \"price\": 185.99, \"importance\": 163 }"),
        JObject.Parse("{ \"gtin\": 11, \"categoryId\": \"cameras\", \"brand\": \"Nikon\", \"colour\": \"Blacks\", \"size\": \"Large\", \"quality\": \"High\", \"price\": 159.99, \"importance\": 113 }"),
        JObject.Parse("{ \"gtin\": 12, \"categoryId\": \"cameras\", \"brand\": \"Nikon\", \"colour\": \"Silvers\", \"size\": \"Small\", \"quality\": \"Low\", \"price\": 69.99, \"importance\": 63 }"),
    };
}

И я заказываю их по важности. В некоторых случаях они имеют одинаковое значение. В этом случае есть 2 продукта со значением 150. Итак, я хочу убедиться, что они правильно упорядочены в этом разделе, поэтому я создал несколько сортировок , которые должны переупорядочить продукты.

public List<Sortation> WhenListSortations()
{
    return new List<Sortation>
    {
        new Sortation
        {
            Field = "colour",
            Expression = "Blacks",
            Order = 0
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Greys",
            Order = 1
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Silvers",
            Order = 2
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Whites",
            Order = 3
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Blues",
            Order = 4
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Pinks",
            Order = 5
        },
        new Sortation
        {
            Field = "colour",
            Expression = "Yellows",
            Order = 6
        },
        new Sortation
        {
            Field = "price",
            Expression = "0",
            Order = 7
        },
        new Sortation
        {
            Field = "latestModel",
            Expression = "Yes",
            Order = 8
        }
    };
}

И я создал пару тестов:

[Test]
    public async Task ShouldHaveHighestImportanceTopAndLowestBottom()
    {
        // Assemble
        var services = SortContext.GivenServices();
        var sortProvider = services.WhenCreateSortProvider();
        var products = services.WhenListProducts();
        var sortations = services.WhenListSortations();

        services.MockSortationProvider.Setup(x => x.ListAsync("cameras")).ReturnsAsync(sortations);

        // Act
        var sortedProducts = await sortProvider.SortAsync(products);

        // Assert
        sortedProducts.First()["importance"].ToString().Should().Be("175");
        sortedProducts.Last()["importance"].ToString().Should().Be("13");
    }

    [Test]
    public async Task ShouldSortEqualImportanceBySortation()
    {
        // Assemble
        var services = SortContext.GivenServices();
        var sortProvider = services.WhenCreateSortProvider();
        var products = services.WhenListProducts();
        var sortations = services.WhenListSortations();

        services.MockSortationProvider.Setup(x => x.ListAsync("cameras")).ReturnsAsync(sortations);

        // Act
        var sortedProducts = await sortProvider.SortAsync(products);

        // Assert
        sortedProducts[0]["importance"].ToString().Should().Be("175");
        sortedProducts[1]["importance"].ToString().Should().Be("163");
        sortedProducts[2]["importance"].ToString().Should().Be("150");
        sortedProducts[3]["importance"].ToString().Should().Be("150");
        sortedProducts[4]["importance"].ToString().Should().Be("125");

        sortedProducts[2]["colour"].ToString().Should().Be("Blacks");
        sortedProducts[3]["colour"].ToString().Should().Be("Silvers");
    }

Мой метод решения этой проблемы выглядит следующим образом:

public async Task<IList<JObject>> SortAsync(IList<JObject> products)
{
    _productListValidator.Validate(products, "gtin", "categoryId", "importance");

    var categoryId = products[0]["categoryId"]?.ToString();
    var sortations = await _sortationProvider.ListAsync(categoryId);
    if (sortations == null || sortations.Count == 0) return products;

    var orderedSortations = sortations.OrderBy(m => m.Order).ToList();
    var orderedProducts = products.OrderByDescending(m => Convert.ToInt32(m["importance"].ToString())).ToList();
    var groups = orderedProducts.GroupBy(m => m["importance"].ToString());

    var sortedProducts = orderedProducts.OrderBy(a => 1);
    foreach(var group in groups)
    {
        if (group.Count() == 1) continue;
        // TODO: re-order the grouped products by sortation
    }

    var t = sortedProducts.ToList();
    return t;
}

В настоящее время выполнение моих тестов с этим кодом пройдет первый тест, но не пройдет последний тест. Итак, я добавил свой код для сортировки 2 продуктов по 150. Выглядело это так:

var groupProducts = group.ToList().OrderBy(a => 1);
var result = orderedSortations.Aggregate(groupProducts,
    (current, sortation) =>
    {
        if (sortation.Field.Equals("price", StringComparison.OrdinalIgnoreCase))
            return sortation.Expression.Equals("0") ? 
                current.ThenBy(m => Convert.ToDecimal(m["price"].ToString())) :
                current.ThenByDescending(m => Convert.ToDecimal(m["price"].ToString()));

        return current.ThenByDescending(m => m.ContainsKey(sortation.Field) && m[sortation.Field].ToString().Equals(sortation.Expression));
    }).ToList();
var gtins = result.Select(m => m["gtin"].ToString()).ToList();
sortedProducts = sortedProducts.ThenBy(m => gtins.IndexOf(m["gtin"].ToString()));

Таким образом, полный метод выглядит следующим образом:

public async Task<IList<JObject>> SortAsync(IList<JObject> products)
    {
        _productListValidator.Validate(products, "gtin", "categoryId", "importance");
    var categoryId = products[0]["categoryId"]?.ToString();
    var sortations = await _sortationProvider.ListAsync(categoryId);
    if (sortations == null || sortations.Count == 0) return products;

    var orderedSortations = sortations.OrderBy(m => m.Order).ToList();
    var orderedProducts = products.OrderByDescending(m => Convert.ToInt32(m["importance"].ToString())).ToList();
    var groups = orderedProducts.GroupBy(m => m["importance"].ToString());

    var sortedProducts = orderedProducts.OrderBy(a => 1);
    foreach(var group in groups)
    {
        if (group.Count() == 1) continue;

    var groupProducts = group.ToList().OrderBy(a => 1);
    var result = orderedSortations.Aggregate(groupProducts,
        (current, sortation) =>
        {
            if (sortation.Field.Equals("price", StringComparison.OrdinalIgnoreCase))
                return sortation.Expression.Equals("0") ? 
                    current.ThenBy(m => Convert.ToDecimal(m["price"].ToString())) :
                    current.ThenByDescending(m => Convert.ToDecimal(m["price"].ToString()));

            return current.ThenByDescending(m => m.ContainsKey(sortation.Field) && m[sortation.Field].ToString().Equals(sortation.Expression));
        }).ToList();
    var gtins = result.Select(m => m["gtin"].ToString()).ToList();
    sortedProducts = sortedProducts.ThenBy(m => gtins.IndexOf(m["gtin"].ToString()));
    }

    var t = sortedProducts.ToList();
    return t;
}

Проблема в том, что, хотя он и правильно заказывает 2 продукта, он помещает их в конец моего списка :( Может ли кто-нибудь помочь мне с сортировкой в ​​текущей позиции?

Вы должны быть в состоянии взять код и запустить его, дайте мне знать, если вам нужна дополнительная информация.

1 Ответ

0 голосов
/ 04 ноября 2018

Думаю, мне удалось это сделать. Мой метод был в порядке, я просто должен был отсортировать по важности после Я сделал сортировку:

return sortedProducts.OrderByDescending(m => Convert.ToInt32(m["importance"].ToString())).ToList();

Я удалил первый экземпляр этого вызова, и он работал нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...