Professional > Interview scripting > Writing interview scripts > Dealing with errors > Using a custom validation function > Checking for unique ranks in a categorical ranking grid
 
Checking for unique ranks in a categorical ranking grid
Ranking grids are grids in which you ask respondents to rank or rate items in priority order. This topic offers some validation functions that you can use for ensuring that every item in a grid is ranked with a unique categorical rank.
The questions are defined as follows:
RankGrid "Please rank the following brands for Value for Money." loop
{
BrandA "Brand A", BrandB "Brand B", BrandC "Brand C", BrandD "Brand D"
} fields
(
Rank "Ranking" categorical [0..1]
{
r1 "1st",r2 "2nd", r3 "3rd", r4 "4th", r5 "5th"
};
) expand grid;
DuplicateRanks "Please check your answers - you have duplicate selections
for the following column(s)... {Dups}" info;
MissingRanks "Some brands have not been ranked." info;
This creates a grid with columns labeled 1st to 5th. Ratings are made by clicking in one column per brand. Notice, however, that there are only four brands to be rated, so the 5th rating is superfluous. The routing statements that display and validate the grid suppress this column and are as follows:
IOM.LayoutTemplate = "Card_Blue_TopAndBottomErrors.htm"
RankGrid[..].Rank.Categories.Filter = MatchColumnsToRows(RankGrid)
RankGrid[..].Rank.Categories[..].Label.Style.Width = "3em"
RankGrid.Ask()
Function MatchColumnsToRows(LoopQ)
' Match the number of ranks to the number of categories (Questions/Rows)
' of the grid
Dim i, Filt
LoopQ.Validation.Function = "UniqueRank"
For i = 0 to LoopQ.Categories.Count - 1
Filt = Filt + LoopQ[i].Item[0].Categories[i]
Next
MatchColumnsToRows = Filt
End Function

Function UniqueRank(LoopQ, IOM, Attempt)
'Check for duplicate values in columns
Dim GridCat ' A category to be ranked
Dim Rankings ' List of different rankings applied to a category;
' duplicates appear once only
Dim DupRankLabel ' Labels for columns containing duplicate rankings
Dim NumRankings ' Number of rankings checked
Dim DupRankings ' List of duplicate rankings for a category
Dim NumDups ' Number of duplicate rankings
Dim ThisDupRanking ' A ranking in the list of duplicate rankings
Dim ThisRanking ' A ranking in the list of possible rankings
' Clear errors collection
LoopQ.Errors.Clear()

' Check for duplicate rankings in a column
For Each GridCat in LoopQ.Categories
If Not LoopQ[GridCat].Item[0].Response.Value = Null Then
If Len(Intersection(Rankings, _
LoopQ[GridCat].Item[0].Response.Value)) > 0 Then
DupRankings = _
Union(DupRankings,LoopQ[GridCat].Item[0].Response)
End If
NumRankings = NumRankings + 1
End If
Rankings = Union(Rankings,LoopQ[GridCat].Item[0].Response.Value)
Next

' Build list of rankings that have been duplicated
If Len(DupRankings) >0 Then
For Each ThisRanking in LoopQ[0].Item[0].Categories
For Each ThisDupRanking in DupRankings
If ThisDupRanking = _
LoopQ[0].Item[0].Categories[ThisRanking].Value Then
DupRankLabel = DupRankLabel + _
LoopQ[0].Item[0].Categories[ThisRanking].Label + ", "
End If
Next
Next
End If

' Update error messages and set success/failure of validation
If Len(Rankings) < NumRankings Or _
NumRankings < LoopQ.Categories.Count Then
If Len(Rankings) < NumRankings Then
DupRankLabel = Left(DupRankLabel,Len(DupRankLabel)-2)
IOM.Questions["DuplicateRanks"].Label.Inserts["Dups"].Text = _
DupRankLabel
LoopQ.Errors.AddNew("DuplicateRanks", _
IOM.Questions.DuplicateRanks.Label)
End If
If NumRankings < LoopQ.Categories.Count Then
LoopQ.Errors.AddNew("MissingRanks", _
IOM.Questions.MissingRanks.Label)
End If
UniqueRank = False
Else
UniqueRank = True
End If
End Function
We'll discuss this code in more detail shortly. First, here’s what it does if the respondent submits invalid or incomplete rankings. Notice also that the 5th ranking column is not displayed.
Ranking grid showing errors
Now we'll look at the validation function is detail.
This example uses the Card_Blue_TopAndBottomErrors template that is installed with UNICOM Intelligence Interviewer - Server. If you use this code with your own templates you should ensure that they show top errors for the grid otherwise the error messages will not be shown. For more information, see Error messages for questions in loops and blocks.
In the MatchColumnsToRows function, the loop steps through each item in RankGrid’s loop control list in turn. Items in the control list are numbered from zero so the For statement takes this into account. For each item in the control list, the function selects the rank in the corresponding position in the Ranking question and adds it to the filter. The function never reaches the fifth ranking because there are only four brands to be ranked.
Note This is a very useful function in scripts that use filtering because it means that you can use the same ranking grid for all respondents, and the function will ensure that the number of ranking columns matches the number of items the respondent is being asked to rank.
The UniqueRank function is more complex and performs the bulk of the validation work.
First, it clears the errors collection for the grid in case this is not the first time that the respondent has submitted invalid rankings.
Then, the For loop checks for duplicate rankings in a column.
Each brand is checked to see whether it has the same ranking as a previous brand. The loop uses the Intersection function for this. The Intersection function compares lists of categorical items (in this case Ranking, which is the list of unique ranks so far, with the ranking for the current brand) and returns a list of items that are present in both lists. If this list is not empty the current ranking is a duplicate of a previous one.
When a duplicate ranking is found, the list of duplicates in DupRanking is updated using the Union function. This function compares categorical lists and returns a list of items that are present in one or more of the lists.
The loop ends by incrementing the number of ranks it has checked and updating the list of ranks so far in Ranking.
Next, the function looks at the list of duplicate rankings.
If there are duplicates, the function builds a list of the relevant rank labels ready for insertion in the error message. It builds the list by looping through the list of ranks and comparing each duplicate rank (ThisDupRank) with the current rank in the list (ThisRanking). When a match is found, the rank’s label is added to the list in DupRankList.
Finally, UniqueRank sets its return value according to whether the categories have been ranked correctly.
There are two types of errors that can occur, either separately or together — duplicate ranks, and unranked categories. For duplicate ranks, the function removes the trailing comma and space from the list of duplicates, updates the DuplicateRanks error message with this list, and adds the error message to the errors collection. For unranked categories, the function simply adds the MissingRanks error to the errors collection. The return value for the function is then set accordingly.
See also
Using a custom validation function