Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Запрос к таблице с n столбцов 
:(
    Опции темы
swetik1981
Дата 8.2.2013, 06:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 117
Регистрация: 20.12.2007

Репутация: нет
Всего: нет



Мною написана функция, которая выбирает уникальные значения в заданном пользователем столбце таблицы и подсчитывает количество соответствующих им уникальных значений во всех остальных столбцах.


    
Код

Function statArray(ByVal dTable As DataTable, ByVal numMainCol As Integer) As System.Array

        'Создаю массив имен столбцов в таблице, по которым будет произведен подсчёт статистики (все кроме основного столбца, по которому будет осуществляться группировка)
        Dim addCols(dTable.Columns.Count - 1) As String
        Dim numAddCol As Integer = 0 'Счётчик статистических столбцов
        For i = 0 To dTable.Columns.Count - 1
            If i <> numMainCol Then
                numAddCol = numAddCol + 1
                addCols(numAddCol) = dTable.Columns(i).ColumnName
            End If
        Next

        'LINQ-запросы на подсчет статики по каждому столбцу (можно, конечно, объединить всё в один запрос, но так будет более понятно)

        Dim q1 = From dt In dTable _
                        Group dt.Field(Of Object)(addCols(1)) By f_by = dt.Field(Of Object)(dTable.Columns(numMainCol).ColumnName) _
                        Into cnt = Count() _
                        Select ff = f_by, cnt = cnt

        Dim q2 = From dt In dTable _
                        Group dt.Field(Of Object)(addCols(2)) By f_by = dt.Field(Of Object)(dTable.Columns(numMainCol).ColumnName) _
                        Into cnt = Count() _
                        Select ff = f_by, cnt = cnt

        Dim q3 = From dt In dTable _
                        Group dt.Field(Of Object)(addCols(3)) By f_by = dt.Field(Of Object)(dTable.Columns(numMainCol).ColumnName) _
                        Into cnt = Count() _
                        Select ff = f_by, cnt = cnt

        'Теперь объединяющий запрос, собирающий статистику по всем столбцам в одну таблицу
        Dim query = From dt1 In q1 _
                  Join dt2 In q2 On dt2.ff Equals dt1.ff _
                  Join dt3 In q3 On dt3.ff Equals dt1.ff _
                Select main = dt1.ff, f1 = dt1.cnt, f2 = dt2.cnt, f3 = dt3.cnt

        'Возврат массива
        statTable = query.ToArray

    End Function




То есть, для таблицы:

Код

Table1

F     I    O        Year

Иванов     Сергей    Иванович    1980
Иванов     Олег    Петрович    1981
Иванов     Кирилл    Семенович    1980
Петров     Сергей    Семенович    1982
Петров     Кирилл    Семенович    1980
Сидоров Сергей    Иванович    1983
Сидоров Иван    Петрович    1980



при запуске функции:

Код

Dim Itog=statArray(Table1, 0)


Я получаю результат:

Код

Main      fl1     fl2     fl3    

Иванов    3       3       2 
Петров    2       1       2
Сидоров   2       2       2


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


Код

Dim Itog=StatArray(Table1, 1)

выдаст:

Код

Main      fl1     fl2     fl3    

Сергей    3       2       3 
Олег      1       1       1
Кирилл    2       1       1
Иван      1       1       1


И так далее по всем четырём столбцам.

Функция работает, но только на таблицу с четырьмя столбцами. Для того, чтобы перестроить функцию под другое количество столбцов, необходимо менять код. 
ВОПРОС: Можно ли как-то посредством LINQ-запроса(ов) сделать аналогичную, но универсальную функцию, которая работала бы с таблицами с любым количеством столбцов и при этом выдавала бы статистику по всем столбцам аналогично, как в приведенном выше случае?

PM MAIL   Вверх
swetik1981
Дата 23.2.2013, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 117
Регистрация: 20.12.2007

Репутация: нет
Всего: нет



Неужели эта задача не разрешима?
PM MAIL   Вверх
KelTron
Дата 28.2.2013, 08:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 745
Регистрация: 8.10.2006
Где: Красноярск

Репутация: 2
Всего: 38



Вот, работает для любого количества столбцов:

Код

class Program
{
    static void Main(string[] args)
    {
        var initialData = CreateInitialData();

        Console.WriteLine("Initial:");
        PrintDataTable(initialData);

        Console.WriteLine();
        Console.WriteLine("Result:");
        PrintDataTable(CalculateStatistics(initialData, 3));

        Console.ReadLine();
    }

    private static DataTable CreateInitialData()
    {
        var table = new DataTable();
        table.Columns.Add(new DataColumn("F", typeof(string)));
        table.Columns.Add(new DataColumn("I", typeof(string)));
        table.Columns.Add(new DataColumn("O", typeof(string)));
        table.Columns.Add(new DataColumn("Year", typeof(int)));

        table.Rows.Add("Иванов", "Сергей", "Иванович", 1980);
        table.Rows.Add("Иванов", "Олег", "Петрович", 1981);
        table.Rows.Add("Иванов", "Кирилл", "Семенович", 1980);
        table.Rows.Add("Петров", "Сергей", "Семенович", 1982);
        table.Rows.Add("Петров", "Кирилл", "Семенович", 1980);
        table.Rows.Add("Сидоров", "Сергей", "Иванович", 1983);
        table.Rows.Add("Сидоров", "Иван", "Петрович", 1980);

        return table;
    }

    private static DataTable CalculateStatistics(DataTable table, int mainColInd)
    {
        var res = new DataTable();
        res.Columns.Add(new DataColumn("Main", typeof(string)));
        res.Columns.AddRange(Enumerable.Range(1, table.Columns.Count - 1)
            .Select(n => new DataColumn("fl" + n, typeof(int)))
            .ToArray());

        var checkColumns = table.Columns.Cast<DataColumn>().Where((col, ind) => ind != mainColInd).ToArray();
        var mainValues = table.AsEnumerable().Select(r => r[mainColInd]).Distinct();

        foreach (var value in mainValues)
        {
            var row = res.NewRow();

            int resColPos = 0;
            row[resColPos++] = value;

            foreach (var col in checkColumns)
            {
                row[resColPos++] = table.AsEnumerable()
                    .Where(r => r[mainColInd].Equals(value))
                    .Select(r => r[col])
                    .Distinct()
                    .Count();
            }

            res.Rows.Add(row);
        }

        return res;
    }

    private static void PrintDataTable(DataTable table)
    {
        const int colWidth = 15;

        Console.WriteLine(string.Join("", table.Columns.Cast<DataColumn>().Select(c => c.ColumnName.PadRight(colWidth))));

        Console.WriteLine(new string('-', colWidth * table.Columns.Count));

        foreach (var row in table.AsEnumerable())
        {
            Console.WriteLine(string.Join("", row.ItemArray.Select(c => c.ToString().PadRight(colWidth))));
        }
    }
}




--------------------
Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог.
Эвенгар Салладорский, основатель Школы Тьмы.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | LINQ (Language-Integrated Query) | Следующая тема »


 




[ Время генерации скрипта: 0.1136 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.