Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

(Solved) Applying variables to string

Discussion in 'Scripting' started by L_A_R, Jan 21, 2020.

  1. L_A_R

    L_A_R

    Joined:
    May 14, 2017
    Posts:
    34
    This works fine:
    - When the ChangeLetter method is run, it works as expected a new letter from the array is seen in Debug.
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Tester : MonoBehaviour
    4. {
    5.     string Letter;
    6.     string[] Letters = new string[5] { "d", "e", "x", "y", "z" };
    7.     string QuestionString;
    8.  
    9.     public void ChangeLetter()
    10.     {
    11.         Letter = Letters[Random.Range(0, Letters.Length)];
    12.         QuestionString = Letter;
    13.         Debug.Log(QuestionString);
    14.     }
    15. }
    Problem:
    When getting the question/strings format from a List of strings instead i get null.
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class Tester : MonoBehaviour
    5. {
    6.     string Letter;
    7.     string[] Letters = new string[5] { "d", "e", "x", "y", "z" };
    8.     string QuestionString;
    9.     public List<string> Questions = new List<string>();
    10.  
    11.     private void Start()
    12.     {
    13.         SetQuestions();
    14.     }
    15.  
    16.     public void ChangeLetter()
    17.     {
    18.         Letter = Letters[Random.Range(0, Letters.Length)];
    19.         QuestionString = Questions[0];
    20.  
    21.         Debug.Log(QuestionString);
    22.     }
    23.  
    24.     void SetQuestions()
    25.     {
    26.         Questions.Add(Letter);
    27.         Questions.Add(Letter + Letter);
    28.         Questions.Add(Letter + Letter + Letter);
    29.     }
    30.  
    31. }
    Question:
    I am trying to create a list of questions (strings) and have them vary as their variables are changed e.g. "Letter = Letters[Random.Range(0, Letters.Length)];" - How is this done correctly please?

    Reason for wanting the list of strings:
    I want to use strings as a template for hundreds of questions, when a question is generated that template is pulled from the list in the desired place - this is to avoid generating each question over and over whilst only using one at a time.
     
  2. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    302
    Code (CSharp):
    1.     void SetQuestions()
    2.     {
    3.         Questions.Add(Letter);
    4.         Questions.Add(Letter + Letter);
    5.         Questions.Add(Letter + Letter + Letter);
    6.     }
    Letter
    is an empty string right? You didn't initialize it to anything in the declaration, so maybe the contents of the
    Questions
    list are null when you try to access it in
    ChangeLetter()
     
  3. L_A_R

    L_A_R

    Joined:
    May 14, 2017
    Posts:
    34
    I don't know how to get around it. I am wanting to use a list of strings as templates for sentences, these contain variables (e.g. Letter) then the relevant string is pulled from the list of strings, the variables are applied to it and they can change (e.g Letter = Letters[Random.Range(0, Letters.Length)];)

    I just need to know the correct way to do that. I can get the strings from the lists but I cannot get them to update when their variables are changed.
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    That's the key there. Strings are a value type (like int, float, etc), not a reference type (like most classes). That means that when you set a string to another string, the value is copied to the new one. So in a simple example:
    Code (csharp):
    1. string a = "a1";
    2. string b = a;
    3. a = "a2";
    4. Debug.Log(b); // Prints "a1"
    So if you want the "full list of questions" string to update when its component strings are changed, you need to rebuild it either every time it's accessed, or every time a component string changes.

    I recommend googling C#'s StringBuilder class, which is designed to efficiently do exactly this kind of thing.
     
    L_A_R likes this.
  5. L_A_R

    L_A_R

    Joined:
    May 14, 2017
    Posts:
    34
    StarManta thank you so much for your response and your explanatory example (which I understand and further to that, understand what I misunderstood).

    In trying to solve this, I have done so with Regex but (my use) is ugly but functional. I have tried string.Replace and I have come across StringBuilder and now that will be my focus. One of my main problems has been "I can solve this but I do not know which is the best way nor do I know the most efficient way" and now I do so I can't thank you enough! I wish I'd bumped into you earlier.
     
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    String is actually kinda special. It's a reference type but with some unusual rules.

    Your example code doesn't really demonstrate anything; you'd get the same result for both value types and reference types, because you're just doing variable assignments.
    Code (CSharp):
    1. SomeClass a = new SomeClass(1);
    2. SomeClass b = a;
    3. a = new SomeClass(2);
    4. // b still refers to the object instantiated on line 1
    5. // a now refers to an entirely new object instantiated on line 3
    The difference comes in when you change something about the underlying object (not just the variable):
    Code (CSharp):
    1. SomeClass A = new SomeClass();
    2. A.someField = 3;
    3. SomeClass B = A;
    4. A.someField = 7;
    5. Debug.Log(B.someField); // prints 7
    6. // With reference types (like classes), B is an alias of A, so changes to A are reflected in B
    7. // With value types (like structs), B would have been a copy of A, so changing A
    8. // would have had no effect on B (and we'd print 3 instead of 7)
    As for strings: in C#, strings are a reference type, but string objects are immutable, meaning that you can't ever change them after they've been created. (Any function that looks like it is modifying a string is actually creating and returning a new string.) So examples like the one above where you change something about the object can't even happen in the first place! In ordinary situations, you can't actually tell from your code's output whether strings are value types or reference types, because the operations that would let you tell the difference are illegal. (There are some "under the covers" differences, though; mostly for performance.)
     
    L_A_R and Joe-Censored like this.
  7. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    For simple substitutions, your easiest option is probably string.Format(), which lets you supply a "template" that says where variables will get inserted.

    Code (CSharp):
    1. string productName = "coconut";
    2. int productPrice = 3;
    3.  
    4. string message = string.Format("One {0} costs {1} dollars", productName, productPrice);
    5.  
    6. Debug.Log(message);
    7. // prints "One coconut costs 3 dollars"
    There are special codes you can use to control how variables get formatted.

    Notice that what I'm calling the "template" is just a string, and could, itself, be a variable.
    Code (CSharp):
    1. string productName = "coconut";
    2. int productPrice = 3;
    3. string template = "One {0} costs {1} dollars";
    4.  
    5. string message = string.Format(template, productName, productPrice);
    6.  
    7. Debug.Log(message);
    8. // prints "One coconut costs 3 dollars"
     
    L_A_R likes this.
  8. L_A_R

    L_A_R

    Joined:
    May 14, 2017
    Posts:
    34
    Antistone, first of all thank you for your replies they're more valuable to me than you perhaps realise. If I for example had just seen this days ago you would have saved me double-digits of hours of frustration and confusion.

    I want to be good at coding (in the context of unity/c# as a focus) not just 'passable' as I'm tired of running into roadblocks because I have built a poor foundation. I would like to be of a standard and understanding where I can break things down as you can and have here.
    What do you think would be a good place/resource to start at/with?
    I will do any course or work through block of work you recommend as a starting point. (I don't want you to go out of your way and find me anything more just...if you were to direct yourself from the past where to start where would it be?)

    Thank you for any advice and again for your insight here.
     
    Last edited: Jan 22, 2020
  9. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Glad that was helpful.

    I'm afraid I'm not much good at recommending introductory materials for new programmers. I started programming when I was a kid, so I don't have a good conception of what order you should learn things in, and the actual sources I used are generally both out-of-date and unavailable today.

    The one point I usually hammer on for newbies is that computers are like evil genies: They give you exactly what you ask for, not what you meant. Computers do not have common sense and do not infer your end goal. Every piece of code that you type has a formal, precise, mathematically-rigorous meaning, and the computer is going to follow it to the letter (no matter how ridiculous the outcome).