Comparing lists index bug

Hello,

I trying to compare 2 lists by validation condition, but when I testing it in designer i got different result like when it is on server.
Looks like when running test on designer list index starting on number 1, when running interview on server list index starting on number 0.

To get same result, validation condition should be like this:

when testing on designer:

IsAnswered(ListA) ? (ListA.All(x=>x.Item2 == ListB[x.Item1-1].Item2)) : true

when testing on server:

IsAnswered(ListA) ? (ListA.All(x=>x.Item2 == ListB[x.Item1].Item2)) : true

Maybe it is same problem as I wrote befor but I found differences also in export.
When I export data for first time List starting with index 1, but when I prefill list data to new interview, then new list data in export starting by index 0.

Different objects have different indexing schemes. See here for more details on preloading.

Hello martinb,
Your validation condition is too sensitive for removing existing answers. Deleting of elements from the top of a list is not triggering index recalculation of left elements. Try to use something like that:

IsAnswered(ListA) ? ListA.Select(x=>x.Item2).SequenceEqual(ListB.Select(x=>x.Item2))

Hello vfedoseev,
I know its too sensitive but this is exactly what I want. I dont want to allow delete records, only add new one. I know this is not standard way how to do it but it works. I need to implement protected variables.

@arthurshaw2002 @sergiy Thanks for answers, I understand that IDs are generated automaticaly and there could be gaps. Looks like I made a mistake during prefilling via API.

Still I think so, there are something wrong in designer. Its not okay when I get different validation condition result in designer-testing like when interview is uploaded on server. You can simply simulate it by testing this validation
IsAnswered(ListA) ? (ListA.All(x=>x.Item2 == ListB[x.Item1-1].Item2)) : true

I`m trying to prefill list question via API but I dont know how ti write down if there is a gap.

I was trying to write down as null or "" but it doesnt work.


{AssignmentIdentifyingDataItem { 
Identity = , 
Variable = List_osob, 
Answer = [null,"aaa",null,"bbb",null,null,null,"ccc"] }}

Do you have any idea what am I doing wrong?
Thank you.

@martinb Thank you for your question, and I will extend it.

@arthurshaw2002 @sergiy When conditions are programmed in the Designer (enabling, validating or filtering) using the expression list[index],

Can it be assumed in all cases that the index of the first element is 0 (and not 1)?

If I type roster_name[0] do I always get the first row in the roster?

The code corresponding to the first item in the list is:

q.First().Item1

or completely equivalently

q.First().Value

Why do you need to know the particular value? To force that person to be household head?

Thank you @sergiy, we use index in the following cases:

  1. Having a list source roster with a fixed set of items, and from a question outside the roster, query the response value of a question for a particular item, for example: roster[(int)3].question

  2. In other cases, we use it to query information associated with a variable, which is stored in a lookup table or in an arrange, for example: table[(int)col1].col2 or arrange[(int)col1].col2

  3. To filter response categories by filtering by person characteristics that are stored in a person roster, for example: people_roster[(int)@optioncode].parentage.InRange(1,14) && people_roster[(int)@optioncode].age>=18

  4. To obtain information about a specific person who was selected from a people roster (by means of a single selection question, with categories extracted from a list-type question, which is in turn a source of the people roster list), for example: people_roster[ (int)selected_person].phone.Length

As I understand instead of this:

you can write simply:

age>=18

and through that avoid the indexing completely.

Your use case Nr 4 is exactly as it is intended and is independent of how the items are numbered. Even if at some point we change ids to be 32 digits long that should continue to work.

Your use cases Nr 1 is not clear. How will the condition work if there are less than 3 persons in the roster? Where is this constant 3 coming from?

In reference to lookup tables (Nr.2) indexing is not relevant. You address by key, and the keys are those values that you’ve uploaded (in the rowcode column). I am not sure what an ‘arrange’ is. Perhaps a C# array? But no variable may have type array.

Best, Sergiy

Just for better specification of my problem and what I tryed to do…
It looks like API is not supporting list question with gap. Or I just dont know syntax how to write down?
Thank you.

[Test]
        public async Task should_be_able_to_create_assignment_with_answer()
        {
            var creationResult = await this.service.Assignments.CreateAsync(new CreateAssignmentRequest
            {
                QuestionnaireId = questionnaireIdentity,
                Quantity = 5,
                Responsible = "inter",
                IdentifyingData = new List<AssignmentIdentifyingDataItem>
                {
                    new AssignmentIdentifyingDataItem // list question no gap
                    {
                        Variable = "listR1",
                        Answer = JsonSerializer.Serialize(new []{ "one", "two", "three" })
                        /* this syntax is working */
                    },
                    new AssignmentIdentifyingDataItem //  list question with gap? 
                    {
                        Variable = "listR2",
                        Answer = JsonSerializer.Serialize(new [] { "1 -> one", "3 -> three" })    
                        //this syntax is not working 
                        Answer = JsonSerializer.Serialize(new [] { null, "one", null,  "three" }) 
                        //this syntax is not working 
                        Answer = JsonSerializer.Serialize(new [] { "", "one", "",  "three" })     
                        //this syntax is not working 
                    }
                }
            });

An answer to the question of type list is a sequence of string values, {s1,s2,…,sk} all of which are not empty (not null, not “”).

You can’t preload a list question with an empty value/values (if this is what you are trying to do).

Neither API nor interactive data entry.

So how can I prefill items (members) from export if ID of items could contain a gaps? As you explain it here (bellow) I need to know IDs of members for next export to merge data from different exports. So if there could be a gap if first ID = 5 “John” how can i prefill this ID to interview? Then I have to specify somewhere else item ID.

Another thing what I dont understand is, if I test interview in designer, list question starts with index 1, same if I fill list question manualy by tablet on interview. But if I prefill list question by API like this:

it will be start by index 0 so thats why I want to prefill list question with first empty (null) item.

In this case I’d recommend to preload a hidden variable in the roster with your specific personid created in the sample that you upload and not involve the ids created by Survey Solutions to the merges task.

Ok, but there are still problem with indexing list items when list is prefilled.
Here is an example:


Index of bb = 2

If I prefill data:


Index of Monika is 1

Its same questionaire…
here is syntax how I check person index and name

So if i want use something like this


If I prefill data (members) I have to use @rowcode -1
if members are not prefilled I have to use @rowcode

This is a problem what I was writing in my first post where you can see that exported data are also affected.

Solution:
Create hidden question → If prefilling list than I have to prefill hidden question

  • if question is prefilled → @rowcode -1
  • if question is empty → @rowcode

I think there is a misunderstanding here. If you are preloading the list of people, then my recommendation was to preload their IDs into a hidden question, alongside the visible names, such as:

visible    hidden
JOHN       "AB121298"
MARY       "MK129182"

Alternatively, this could have been panel sample IDs, not document IDs:

visible    hidden
JOHN       "002311"
MARY       "002312"

See also protecting pre-loaded answers, which is devised specifically for this case.

But if you’ve figured out a different solution, good for you, just, perhaps leave a more detailed description for the others to use.

Yes, I`m using protected pre-loaded answers to resolve this issue. Its not neceserry to add extra ID in hidden question now. Just use validation condition to check if the member name is unique.

What I have to do is create a hidden question for changing index of list, if list question was preloaded.
(As I wrote before first list member have index 1 but if the list is prefilled first member index is 0.)
So if I want to preload list question I have to also preload this hidden question to fix index. If I call member later in questionaire by index, I will just change index depend of hidden question (list_preloaded).

For example:
if I want to get name of member frol list I will use this variable

IsAnswered(list_preloaded) ? 
(List_member[(int)ID_RO-1].Text) : (List_member[(int)ID_RO].Text)

Hello,

I won`t like to bother you again with this issiue but I still fighting with indexes, I have no idea how to figure it out. Its not possible to preload data properlly if export contain some preloaded data (interviews) and some new data (interviews).

When I export data and I want to create new assignment with preloaded data I have to know indexes properly because when I creating preloaded data I have to do something like this

L_data.Add(new AssignmentIdentifyingDataItem // text 
 {
     Variable = list_Qid[IndexCopyTo].varname.ToString(),
     Identity = new Identity(Guid.Parse(list_Qid[IndexCopyTo].publickey), rosterVector),
     Answer = prefill_answer[i].ToString()
 });

example:

     Variable = abc,
     Identity = fc1a5cd1b4bb4c2494ce207ba728fbbc_0,
     Answer = aaa

The problem is with (identity) rosterVector. When prefilling first RosterVector should by 0 and I dont know from exported data if Identity rosterVector should be “Osoba_nova__id” or “Osoba_nova__id” -1
Because If I prefilled interview it will be start at index 0 if it was not prefilled index will be 1 like on the picture bellow.

Not prefilled interviews:
image

Prefilled interviews:
image

Like I found in help index should be always start from 0 if it isnt subordinate…

  1. text list: the subordinate file should contain the items with sequential ids starting from one (1). Note that the text list question itself requires indexing of members starting with zero (0).

Do you have any idea how can I fix this?

Thank you.