C #: Как вы извлекаете диапазон значений в разреженном списке? [Дубликат]

Список выбора SQL должен быть исправлен во время написания запроса. Вы не можете сделать SQL, который автоматически расширяет свои столбцы на основе найденных данных.

Но ваш запрос является общим, он называется сводной таблицей или таблицей кросс-таблицы.

Единственное решение состоит в том, чтобы сделать это несколькими этапами:

  1. Запрос для обнаружения различных идентификаторов поддонов.
  2. Использовать код приложения для построения динамического SQL-запроса с таким количеством столбцов, как отличные значения идентификатора паллет, найденные в первом запросе.
  3. Запуск результирующего динамического SQL-запроса.

Это справедливо для всех баз данных SQL, а не только для MySQL.

См. MySQL pivot row в динамическое число столбцов для высокопринятого решения для создания запроса сводной таблицы в MySQL.

Я не голосую ваш вопрос как дубликат этого вопроса, потому что ваш запрос также включает transport_id, что сделает решение для запросов немного другим. Но вы должны прочитать о других решениях с поворотным столом.

4
задан ChrFin 22 May 2014 в 13:05
поделиться

3 ответа

Вы можете решить проблему, дважды используя адаптированный бинарный поиск на Keys, чтобы найти индексы, которые связывали интересующий диапазон в коллекции Keys.

Поскольку IList<T> не предлагайте бинарные средства поиска, которые вам нужно написать самостоятельно. К счастью, есть также возможность украсть готовые реализации из . Как выполнить бинарный поиск в IList .

Вот адаптированная версия, чтобы найти нижнюю границу:

public static int LowerBound<T>(this IList<T> list, T value, IComparer<T> comparer = null)
{
    if (list == null)
        throw new ArgumentNullException("list");

    comparer = comparer ?? Comparer<T>.Default;

    int lower = 0, upper = list.Count - 1;

    while (lower <= upper)
    {
        int middle = lower + (upper - lower) / 2;
        int comparisonResult = comparer.Compare(value, list[middle]);

        // slightly adapted here
        if (comparisonResult <= 0)
            upper = middle - 1;
        else
            lower = middle + 1;
    }

    return lower;
}

Чтобы реализовать UpperBound, просто измените

if (comparisonResult <= 0)

на

if (comparisonResult < 0)

. Теперь это тривиально:

var low = set.Keys.LowerBound(value);
var high = set.Keys.UpperBound(value);

// These extra comparisons are required because the adapted binary search
// does not tell us if it actually found the needle. They could be rolled
// into the methods themselves, but this would require another out parameter.
if (set.Keys[low] != value) ++low;
if (set.Keys[high] != value) --high;

if (low <= high) /* remove keys in the range [low, high] */
2
ответ дан Community 24 August 2018 в 05:45
поделиться

Когда список отсортирован, вы можете использовать двоичный поиск для определения конечных точек вашего интервала. Наихудшим случаем будет O (log n).

3
ответ дан Jonas Jämtberg 24 August 2018 в 05:45
поделиться

Я задавался вопросом, почему SortedList<TKey, TValue> не предоставляет BinarySearch, когда он уже отсортирован ключами. Он также использует сам метод (f.e. In IndexOf), но используемый массив является частным полем.

Итак, я попытался создать для этого метод расширения, посмотрите:

public static class SortedListExtensions
{
    public static int BinarySearch<TKey, TValue>(this SortedList<TKey, TValue> sortedList, TKey keyToFind, IComparer<TKey> comparer = null)
    {
        // need to create an array because SortedList.keys is a private array
        var keys = sortedList.Keys;
        TKey[] keyArray = new TKey[keys.Count];
        for (int i = 0; i < keyArray.Length; i++)
            keyArray[i] = keys[i];

        if(comparer == null) comparer = Comparer<TKey>.Default;
        int index = Array.BinarySearch<TKey>(keyArray, keyToFind, comparer);
        return index;
    }

    public static IEnumerable<TKey> GetKeyRangeBetween<TKey, TValue>(this SortedList<TKey, TValue> sortedList, TKey low, TKey high, IComparer<TKey> comparer = null)
    {
        int lowIndex = sortedList.BinarySearch(low, comparer);
        if (lowIndex < 0)
        {
            // list doesn't contain the key, find nearest behind
            // If not found, BinarySearch returns the complement of the index
            lowIndex = ~lowIndex;
        }

        int highIndex = sortedList.BinarySearch(high, comparer);
        if (highIndex < 0)
        {
            // list doesn't contain the key, find nearest before
            // If not found, BinarySearch returns the complement of the index
            highIndex = ~highIndex - 1;
        }

        var keys = sortedList.Keys;
        for (int i = lowIndex; i < highIndex; i++)
        {
            yield return keys[i];
        }
    }
}

Создайте образец SortedList:

DateTime start = DateTime.Today.AddDays(-50);
var sortedList = new SortedList<DateTime, string>();
for(int i = 0; i < 50; i+=2)
{
    var dt = start.AddDays(i);
    sortedList.Add(dt, string.Format("Date #{0}: {1}", i, dt.ToShortDateString()));
}

DateTime low = start.AddDays(1);   // is not in the SortedList which contains only every second day
DateTime high = start.AddDays(10);

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

IEnumerable<DateTime> dateRange = sortedList.GetKeyRangeBetween(low, high).ToList();

Результат:

04/04/2014
04/06/2014
04/08/2014
04/10/2014

Обратите внимание, что это построенный с нуля и не протестированный, но он может дать вам идею.

4
ответ дан Tim Schmelter 24 August 2018 в 05:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: