Разделить список на списки + ve & -ve с помощью c # - PullRequest
0 голосов
/ 23 мая 2011

У меня есть один список значений + ve и -ve, и мне нужно:

  • отсортировать их
  • преобразовать их в int, я умножаю их на 100:)
  • разбить их на два списка
  • убрать общее значение, это должны быть пара + ve и -ve

например

input = 1.00,2.92,-2.92,3.00,7.56,-7.56,8.00, -100.93, -40.56 ......

Конечная цель:

listA = 1, 3, 8
listB = -4056, -10093

Я ищу предложения по улучшению кода ниже, важны скорость и точность.

var results = new List<decimal>(input.Select(x => x*100 ));
results.Sort();
var listA = results.FindAll(x => ((decimal)x > 0));
var listB = results.FindAll(x => ((decimal)x < 0));
decimal[] FromA_NotIn_B = listA.Except(listB.Select(X => (X = X * -1))).ToArray();
decimal[] FromB_NotIn_A = listB.Except(listA.Select(X => (X = X * -1))).ToArray();

Ответы [ 3 ]

0 голосов
/ 24 мая 2011

Работы:

    static void Main(string[] args)
    {
        double[] input = { 1.00, 2.92, -2.92, 3.00, 7.56, -7.56, 8.00, -100.93, -40.56 };
        IEnumerable<int> intsWithouDuplicates = input.Where(d => !input.Contains(-d)).Select(d => (int)(d * 100)).OrderBy(i => i);
        var listA = intsWithouDuplicates.Where(i => i >= 0);
        var listB = intsWithouDuplicates.Where(i => i < 0);

        listA.ToList().ForEach(Console.WriteLine);
        Console.WriteLine();
        listB.ToList().ForEach(Console.WriteLine);
        Console.ReadKey();
    }
0 голосов
/ 01 июня 2011

Это должно быть намного быстрее и надежно удалять дубликаты.
Я пропустил требование «умножение на 100», поскольку оно не соответствует концепции:

1) Сортировка по значению ABS
2) Сравните с вершиной стека, нажмите, если совпадение, нажмите иначе.
3) В конце процесса стек содержит только элементы без совпадения

      decimal[] input = new decimal[] { -6, 1, 2, 3, -1, 2, 2, -2, 6, 7, -4, 4, -7, 8, -4 };
      Stack<decimal> st = new Stack<decimal>();

      IEnumerable<decimal> sorted = input.OrderBy(X => X > 0 ? X : -X);

      foreach (decimal item in sorted)
        if (st.Any() && st.Peek() == -item)
          st.Pop();
        else
          st.Push(item);

      decimal[] pos = st.Where(X => X >= 0).ToArray();
      decimal[] neg = st.Where(X => X < 0).ToArray();
0 голосов
/ 24 мая 2011

Ваш код верен с точки зрения точности (десятичная дробь не теряет точности при инвертировании знака).Его скорость можно уверенно повысить в 20 раз, записав его с помощью циклов и выполнив полное внешнее объединение вручную.Однако я рекомендовал бы это, только если perf критичен, потому что это увеличит размер кода в 5 раз.

Редактировать: объединение слиянием означает одновременное получение двух отсортированных списков и обход по обоим спискам таким образом,элементы могут быть найдены, даже если в обоих массивах есть лишние элементы.Это расширение шага слияния в сортировке слиянием.Полный-внешний означает, что он означает в базах данных: сохраняйте значения, которые есть только в одном из массивов.

Единственное требование, отсортированные списки, является заданным, поскольку вы сортируете список результатов.Ваш код будет работать следующим образом:

var results = new List<decimal>(input.Select(x => x*100 ));
results.Sort();
var listA = new List<decimal>();
var listB = new List<decimal>();

//now to the merge-join and fill listA and B

Объединение слиянием будет сложно реализовать, но для начала вот версия на основе итератора, которую я использую в своем проекте для объединения двух гигантскихфайлы, которые я никогда не смог бы загрузить в память, но которые отсортированы.

    public static IEnumerable<TResult> MergeJoin_OneToOne<TLeft, TRight, TResult>(
        IEnumerable<TLeft> leftCollection,
        IEnumerable<TRight> rightCollection,
        Func<TLeft, TRight, int> comparison,
        Func<TLeft, TResult> onlyLeftSelector,
        Func<TRight, TResult> onlyRightSelector,
        Func<TLeft, TRight, TResult> bothSelector)
    {
        return MergeJoin_OneToOne_Impl(leftCollection, rightCollection, comparison, onlyLeftSelector, onlyRightSelector, bothSelector);
    }

    static IEnumerable<TResult> MergeJoin_OneToOne_Impl<TLeft, TRight, TResult>(
        IEnumerable<TLeft> leftCollection,
        IEnumerable<TRight> rightCollection,
        Func<TLeft, TRight, int> comparison,
        Func<TLeft, TResult> onlyLeftSelector,
        Func<TRight, TResult> onlyRightSelector,
        Func<TLeft, TRight, TResult> bothSelector)
    {
        if (leftCollection == null) throw new ArgumentNullException("leftCollection");
        if (rightCollection == null) throw new ArgumentNullException("rightCollection");
        if (comparison == null) throw new ArgumentNullException("comparison");
        if (onlyLeftSelector == null) throw new ArgumentNullException("onlyLeftSelector");
        if (onlyRightSelector == null) throw new ArgumentNullException("onlyRightSelector");
        if (bothSelector == null) throw new ArgumentNullException("bothSelector");

        using (var leftEnum = leftCollection.GetEnumerator())
        using (var rightEnum = rightCollection.GetEnumerator())
        {
            if (!leftEnum.MoveNext())
            {
                while (rightEnum.MoveNext()) yield return onlyRightSelector(rightEnum.Current);
                yield break;
            }

            if (!rightEnum.MoveNext())
            {
                do
                {
                    yield return onlyLeftSelector(leftEnum.Current);
                } while (leftEnum.MoveNext());
                yield break;
            }

            while (true)
            {
                int cmp = comparison(leftEnum.Current, rightEnum.Current);
                if (cmp == 0)
                {
                    yield return bothSelector(leftEnum.Current, rightEnum.Current);

                    if (!leftEnum.MoveNext())
                    {
                        while (rightEnum.MoveNext())
                        {
                            yield return onlyRightSelector(rightEnum.Current);
                        }
                        yield break;
                    }
                    if (!rightEnum.MoveNext())
                    {
                        do
                        {
                            yield return onlyLeftSelector(leftEnum.Current);
                        } while (leftEnum.MoveNext());
                        yield break;
                    }
                }
                else if (cmp < 0)
                {
                    yield return onlyLeftSelector(leftEnum.Current);

                    if (!leftEnum.MoveNext())
                    {
                        do
                        {
                            yield return onlyRightSelector(rightEnum.Current);
                        } while (rightEnum.MoveNext());
                        yield break;
                    }
                }
                else
                {
                    yield return onlyRightSelector(rightEnum.Current);

                    if (!rightEnum.MoveNext())
                    {
                        do
                        {
                            yield return onlyLeftSelector(leftEnum.Current);
                        } while (leftEnum.MoveNext());
                        yield break;
                    }
                }
            }
        }
    }

По соображениям производительности вы специализируете эту функцию для IList<decimal> элементов.Выбери материал итератора и используй два целых, чтобы представить текущую позицию в списке.При ходьбе listA игнорировать элементы с lt 0 и одинаковыми для B.

Повышение скорости будет происходить благодаря множеству улучшений: распределение объектов значительно сокращено;Операции хеширования, выполняемые Except, исчезли;Никаких лямбд и косвенных указаний.

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