SamuelDexter Ответов: 2

Как оценить числа как 1-е, 2-е и т.д. на основе их значений


hello everyone. 
I am trying to rate a group of numbers in a datagrid containing two columns. I want the cells of the Coulmn B to have values as 1st, 2nd, 3rd etc, based on the values of Column A.

For example:

Col A            Col B
80                    2
305                   1
23                    5
43                    4
31                    3


Что я уже пробовал:

All I know is how to assign the result to the cells of Column B after its found

Dim iRow As Integer
        Dim cellA As Integer
        Dim cellB As Integer

        For iRow = 0 To Me.DataGridView1.RowCount - 1

            Me.DataGridView1.Rows(iRow).Cells(1).Value = cellA
        Next
        iRow = irow + 1

Richard MacCutchan

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

SamuelDexter

Конечно, это самый простой способ уйти. Я согласен но я по некоторым причинам решил отключить сортировку заголовков столбцов в конце концов потому что с помощью общего

Datagridview1.Sort(Datagridview1.Columns(1), System.ComponentModel.ListSortDirection.Восходящий)

никогда не работал на меня; всегда ошибки :(

Richard MacCutchan

- всегда ошибки :("
Затем, пожалуйста, отредактируйте свой вопрос, покажите код и объясните, какие именно ошибки.

SamuelDexter

Система.ArgumentException: "объект должен иметь тип String".

Richard MacCutchan

Так чего же ты не понимаешь?

SamuelDexter

Я понял, что, по-видимому, форма столбца, которую вы сортируете, должна иметь тот же тип данных, что и самый первый столбец. Так например если вы сделали нумерацию листов
на первом вроде бы

' Нумерация

Для r = 0 к DataGridView1.RowCount - 1
DataGridView1.Rows(r).Cells(0).Value = r
Следующий
r = r + 1



поскольку его целое число, то следующий столбец должен иметь свои значения как целое число соответствующим образом, иначе вам нужно будет сделать некоторые преобразования здесь и там, где это необходимо.
Поэтому в этом случае я должен был убедиться, что второй col заполнен целочисленным счетчиком, а записи основного столбца A также были целыми числами.

Кажется, я догадался. Спасибо, чувак. Я благодарен Вам за ваше время и помощь. Овации :)

Richard MacCutchan

Это не имеет смысла, отдельные столбцы могут быть любого типа данных. Метод сортировки будет работать с любым столбцом до тех пор, пока его содержимое можно сортировать; см. Практическое руководство.Метод Сортировки (DataGridViewColumn, ListSortDirection) (System.Окна.Формы)[^].

2 Ответов

Рейтинг:
1

Maciej Los

В дополнение к Ричард Диминг[^] решение и мой комментарий к его решению...

Я бы предложил использовать Словарь[^] объект, когда есть строки с повторяющимися значениями в ColA

Dim dgv As DataGridView = Me.DataGridView1
Dim oDict As Dictionary(Of Integer, Integer) = dgv.Rows().Cast(Of DataGridViewRow) _
	.OrderByDescending(Function(r) r.Cells("ColA").Value) _
	.GroupBy(Function(r) r.Cells("ColA").Value) _
	.Select(Function(grp, index) New KeyValuePair(Of Integer, Integer)(grp.Key, index+1)) _
	.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
	
For Each dgr As DataGridViewRow In dgv.Rows
	dgr.Cells(1).Value = oDict(dgr.Cells(0).Value)
Next


Пример вывода:
80	2
305	1
23	5
43	3
31	4
80	2
305	1
23	5

Как видите, 305 получает 1. ранг, 80 - 2. и так далее...

Удачи вам!

[РЕДАКТИРОВАТЬ]
Что касается комментария Ричарда к моему ответу - небольшое улучшение (все еще используя объект словаря):

Dim oDict As Dictionary(Of Integer, Tuple(Of Integer, Integer)) = dgv.Rows().Cast(Of DataGridViewRow) _
	.GroupBy(Function(r) r.Cells("ColA").Value) _
	.OrderByDescending(Function(g) g.Key) _
	.Select(Function(grp, index) New KeyValuePair(Of Integer, Tuple(Of Integer, Integer))(grp.Key, Tuple.Create(index+1, grp.Count-1))) _
	.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)

For Each dgr As DataGridViewRow In dgv.Rows
	Dim cumulative As Integer = oDict.TakeWhile(Function(x) x.Key>dgr.Cells(0).Value).Sum(Function(x) x.Value.Item2)
	dgr.Cells(1).Value = oDict(dgr.Cells(0).Value).Item1  + cumulative
Next


Результат:
80	3
305	1
23	7
43	5
31	6
80	3
305	1
23	7


Richard Deeming

Правильный рейтинг оставляет пробелы для связей. :)

Представьте себе гонку, где первые два человека пересекают финишную черту одновременно - они совместные первые. Следующий человек, который пересечет линию, является третьим человеком, который пересечет линию, и поэтому занимает третье место.

Maciej Los

Соглашаться. Заявление о 1-м, 2-м и т. д. указало мне неправильное направление ;)
[РЕДАКТИРОВАТЬ]
Обновлено! Спасибо за ваш ценный комментарий.
Овации,
Мацей

Рейтинг:
0

Richard Deeming

Что - то вроде этого должно сработать, и будет правильно ранжировать связи:

Dim cumulativeRank As Integer = 1
For Each group As IGrouping(Of Object, DataGridViewRow) In DataGridView1.Rows.Cast(Of DataGridViewRow)().GroupBy(Function (r) r.Cells(0).Value).OrderByDescending(Function (g) g.Key)
    Dim rank As Integer = cumulativeRank
    For Each row As DataGridViewRow In group
        row.Cells(1).Value = rank
        cumulativeRank += 1
    Next
Next

Если вы не заботитесь о связях, то вам не нужна группировка:
Dim rank As Integer = 1
For Each row As DataGridViewRow In DataGridView1.Rows.Cast(Of DataGridViewRow)().OrderByDescending(Function (r) r.Cells(0).Value)
    row.Cells(1).Value = rank
    rank += 1
Next


Maciej Los

На первый взгляд: когда datagridview хранит уникальные значения, ваш код в порядке, но когда есть дубликаты, ваш метод "ранжирования" вернет неправильный результат. ;(
Кстати - я смог понять, чего ОП хочет добиться, только прочитав ваш ответ.
А 4!

Richard Deeming

Вот почему есть две версии.

* Используйте вторую версию, если вы не заботитесь о связях - подобно SQL ROW_NUMBER функция.
* Используйте первую версию, если вы делать заботьтесь о связях и хотите, чтобы они были правильно ранжированы - подобно SQL RANK функция.

Если вы хотите что-то похожее на DENSE_RANK, где связи не оставляют пробелов, тогда было бы тривиально адаптировать первую версию:

Dim rank As Integer = 1
For Each group As IGrouping(Of Object, DataGridViewRow) In DataGridView1.Rows.Cast(Of DataGridViewRow)().GroupBy(Function (r) r.Cells(0).Value).OrderByDescending(Function (g) g.Key)
    For Each row As DataGridViewRow In group
        row.Cells(1).Value = rank
    Next
    
    rank += 1
Next

Maciej Los

А... понятно. Вчера было уже поздно...
Голосуют!