https://kotlinlang.org logo
#android
Title
# android
m

Minty

11/08/2017, 11:26 AM
I want to use a json file with a list containing a lot of lists. Each child list contains two unicode strings. I want to be able to access a random list using my Android app
c

czuckie

11/08/2017, 11:36 AM
@Minty Start with a small representation of your data structure, e.g.:
Copy code
{
  "questions": [
    {
      "q": "q1",
      "a": [
        "a1",
        "a2",
        "a3"
      ],
      "ca": 1
    },
    {
      "q": "q2",
      "a": [
        "a1",
        "a2",
        "a3"
      ],
      "ca": 0
    }
  ]
}
And get your system parsing that correctly, then work on selecting random questions from that
then you can scale up and figure out how things may work
you might find, if you have tons of questions, it will be worth while ingesting them into a SQLite database instead of parsing JSON every time you want to get a selection of questions
m

Minty

11/08/2017, 11:38 AM
Copy code
[["Q1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Discussion Method can be used when: \n (A) The topic is very difficult\u00a0 (B) The topic is easy \n (C) The topic is difficult\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (D) All of the above \n ", "C"], ["Q2.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Which of the following is a teaching aid? \n (A) Working Model of Wind Mill\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (B) Tape Recorder \n (C) 16mm Film Projector\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (D) All the above \n ", "D"],
My data is more like this
c

czuckie

11/08/2017, 11:39 AM
what do you think of the data structure?
m

Minty

11/08/2017, 11:40 AM
It's like [["Question1 and choices", "Answer"],["Q2","A"]
c

czuckie

11/08/2017, 11:40 AM
are you in control of the data structure?
or has a client given it you?
m

Minty

11/08/2017, 11:41 AM
It's a question paper data that I extracted using regex from a text file
I converted it to json in Python
Copy code
data = []

for r in re.findall(r"Q\d+.*?(?=Q\d+)", soup.text, flags=re.S):

    data_qa = []

    rs = re.findall(r"Q\d+.*?(?=Answer.*?\:.*?[a-dA-D])", r.strip(), flags=re.S)
    ra = re.findall(r"Answer.*?\:.*?[a-dA-D]", r.strip(), )

    for rse in rs:
   #     print rse
        data_qa.append(rse)



    for rsa in ra:
        if ra.index(rsa) == 0:
#            print("The answer is "+ rsa.replace("Answer", "").replace(":", "").strip())
            data_qa.append(rsa.replace("Answer", "").replace(":", "").strip())
  #  print "__________________________________________________________________"
    data.append(data_qa)

for d in data:
    if len(d)<2:
        data.remove(d)
        print d

jdump = json.dumps(data)

with file("qNa.json", "w+") as f:
    f.write(jdump)
c

czuckie

11/08/2017, 11:42 AM
ok cool, I would recommend for your own sanity sticking with either \u00a0 or \n but not both 😄
this shouldn’t be too tough though
each of the questions could be represented nicely using a
data class Question(val question:String, val answer:String)
m

Minty

11/08/2017, 11:43 AM
So is the above representation any good for quiz type things
[["Question1 and choices", "Answer"],["Q2","A"]
c

czuckie

11/08/2017, 11:43 AM
given that you’re scraping it from a text block, it’ll have to do
the reason I was digging was, if you had the data in a format of question and then a list of answers and the correct answer
you could make the quiz more dynamic and randomise the order of answers etc
but since the question answers are encoded in the question, that’s not really viable
m

Minty

11/08/2017, 11:44 AM
I'm supposed to create the
data class
outside
oncreate
right? Can I do it in the main activity classs?
c

czuckie

11/08/2017, 11:44 AM
you can yeah
m

Minty

11/08/2017, 11:46 AM
But I can call data using
index
in a list. How do I do that with a data class. I still don't understand the concept of data class. i guess I'll have to look it up
c

czuckie

11/08/2017, 11:46 AM
Copy code
class MainActivity : AppCompatActivity() {

    data class Question(val question: String, val answer: String)

    fun parseQuestions(rawQuestionJson: String): List<Question> {
        TODO("Parse json")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        parseQuestions("[[\"Question 1\",\"A\"],[\"Question 2\",\"B\"]]")
    }
}
for example
so if you imagine
class Question(val question:String, val answer:String)
if I did
Copy code
val q1 = Question("q1", "a")
val q2 = Question("q1", "a")
if (q1 == q2) {
   println("They are equal")
}
‘they are equal’ would not be printed
if I used a data class, kotlin will provide equality methods making that pass
data classes are useful for identifying clumps of data that have a particular meaning
once you parse the JSON, you can then go about randomising access to the list
m

Minty

11/08/2017, 11:49 AM
How do I dynamically create q1, q2? Would I parse json on the fly and get the data index I want and assign it to q1
data[2] #question3
c

czuckie

11/08/2017, 11:50 AM
how many questions are you dealing with?
m

Minty

11/08/2017, 11:50 AM
I did a len(data) there seem to be 1457
c

czuckie

11/08/2017, 11:51 AM
that’s an impressive amount of questions
you wouldn’t want to parse that everytime you wanted a question
m

Minty

11/08/2017, 11:51 AM
Question papers from 2004 -2017 lol
c

czuckie

11/08/2017, 11:51 AM
I’d definitely consider whacking the questions in a database, BUT
you should be able to get away with
Copy code
private fun parseQuestions(rawQuestionJson: String): List<Question> {
        val result = mutableListOf<Question>()
        val questionArray = JSONArray(rawQuestionJson)
        for (i in 0..questionArray.length()) {
            val question = questionArray.getJSONArray(i)
            result += Question(question.getString(0), question.getString(1))
        }
        return result
    }
line by line, we create a mutable list to store questions in. We then parse the input JSON (we know it’s a JSONArray) We then iterate over all the child arrays We then add a new Question object to our result list (which we can do because it’s mutable) consisting of the two strings in the child question json array object We then result the result
m

Minty

11/08/2017, 11:54 AM
So, you add created Question object instances to list. That was what was bothering me. Thanks. BTW is JSONArray an inbuilt function?
c

czuckie

11/08/2017, 11:54 AM
Copy code
class MainActivity : AppCompatActivity() {

    data class Question(val question: String, val answer: String)

    private fun parseQuestions(rawQuestionJson: String): List<Question> {
        val result = mutableListOf<Question>()
        val questionArray = JSONArray(rawQuestionJson)
        for (i in 0..questionArray.length()) {
            val question = questionArray.getJSONArray(i)
            result += Question(question.getString(0), question.getString(1))
        }
        return result
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var tenQuestions = parseQuestions("[[\"Question 1\",\"A\"],[\"Question 2\",\"B\"]]").shuffled().take(10)
        
        TODO("Display ten questions")
    }
}
JSONArray is part of
org.json
which is shipped with android
var tenQuestions = parseQuestions("[[\"Question 1\",\"A\"],[\"Question 2\",\"B\"]]").shuffled().take(10)
may look like black magic but
Copy code
var tenQuestions = parseQuestions("...JSONHERE...")
   .shuffled() // Randomises the order of list items
   .take(10) // Take the first 10 items from the list
assuming you want a random collection of questions!
subjecting someone to 1407 questions is going to be brutal lol
if this is to help you revise etc
I would really investigate the possibility of teasing out the answer from the questions
it’ll help you learn the right answer, rather than the right letter 😉
m

Minty

11/08/2017, 11:57 AM
It's a multiple choice. I have created logic for buttons. I check the string A, B,C,D and set the answer int to ,1,2,3,4 and check in Button
What do you mean by teasing out?
c

czuckie

11/08/2017, 11:58 AM
so if all the questions take the format
“This is a question that needs to be answered by one of the following answers: A) Answer A B) Answer B C) Answer C D) Answer D” Correct Answer: C Then I would parse the input data to extract “This is a question that needs to be answered by one of the following answers” the individual answers The correct answer
and I’d transform that into the format I explained above
then you could randomise the display of the answers
since you know what the correct answer is, you always know that if you display answer C first, the first button would be the correct one
any who ! Lunch time, ask questions though!
m

Minty

11/08/2017, 12:00 PM
I can maybe give a option to display answer too. But my main focus is to build a quiz. This is my first Kotlin project and I'm in love with kotlin already
Oh! You mean randomising the order of the choices?
That'll be useful but I have to parse the data first. Regex to the rescue.
But I want to build a simple working project first and add features later
Since this is my first project, I want to take it easy and build the simple parts first (a proof of concept) and add features later
BTW what do I have to import for JSONArray?
Never mind, imported it
c

czuckie

11/08/2017, 1:04 PM
your approach is perfect
build the simplest thing first
go end to end
then beef it up as you go
agile all the way 👍
2 Views