-3

My question about System.Random command in C#.

I have a query in the MVC 4 project like:

public JsonResult GetQuestions() 
{
    ...
    var rnd = new Random();
    var selectedData = data.Select(y => new 
    { 
        ...,
        qAnswers = ((y.qA1 != null ? "ab" : "") + 
                   (y.qA2 != null ? "cd" : "") +
                   (y.qA3 != null ? "ef" : "") +
                   (y.qA4 != null ? "gh" : "") +
                   (y.qA5 != null ? "ij" : "")).OrderBy(item => rnd.Next())
    });

    return Json(selectedData, JsonRequestBehavior.AllowGet); 
}

As a result of the query, I want to see something like:

ijcdefabgh

But the result is:

["i","a","c","d","g","h","e","f","b","j"]

Do you know to where is my mistake? or How can i fix it?

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 1
    you mean you want is as a string but you have an array of strings? – Gilad Green Sep 12 '17 at 13:53
  • There are two portions to this question. First the required output is different from current output which is because of `Random` as it is ordering your columns randomly. You need to remove it. Secondly u are getting are array of strings which need to be concatenated to obtain your desired output using `string.Join` – Abdul Samad Sep 12 '17 at 13:58
  • It would help if this was a https://stackoverflow.com/help/mcve – mjwills Sep 12 '17 at 13:58
  • 2
    This has nothing to do with how you're using Random - so I updated your title. But as a word of warning, you dont want a new instance of Random each request - use one static instance. – Jamiec Sep 12 '17 at 14:00
  • You're generating a single string, then shuffling the contents (characters). You want to generate a collection like a list, then shuffle the contents (strings). – BurnsBA Sep 12 '17 at 14:08
  • @BurnsBA I guess I want to do something like what you say, may you show me to how to do it? – Emirhan ÖZKAN Sep 12 '17 at 14:16
  • 1
    @shA.t: Never order by a guid. Guids are guaranteed to be *unique*; that they are *random* is an implementation detail. A guid provider is permitted to generate *sequential random guids*, and if it does so then your shuffle will shuffle into sorted order. – Eric Lippert Sep 12 '17 at 15:55
  • The reason you got the characters shuffled is because strings are `IEnumerable`, and so the `OrderBy` applied itself to the *sequence of characters*. – Eric Lippert Sep 12 '17 at 15:57
  • @EricLippert Thanks I got it [here](https://stackoverflow.com/q/1651619/4519059) ;). – shA.t Sep 12 '17 at 16:05

2 Answers2

1

You must create a string array in order to have the "pairs" as a string, and then shuffle it,something like:

var qAnswers = String.Concat(new string[] { (y.qA1 != null ? "ab" : "" ),
               (y.qA2 != null ? "cd" : ""),
               (y.qA3 != null ? "ef" : ""),
               (y.qA4 != null ? "gh" : ""),
               (y.qA5 != null ? "ij" : "")}
                 .Where(item=>!string.IsNullOrEmpty(item))
                 .OrderBy(item=>rnd.Next())); 
Pikoh
  • 7,582
  • 28
  • 53
  • That's lovely! My answer here is but before the sign as correct, My I learn why did you use .Where(item => !string.IsNullOrEmpty(item)) command? Also, what does it mean? – Emirhan ÖZKAN Sep 12 '17 at 14:33
  • Because when you are adding strings to the array, in case one `y.qAx` is null, you are going to add an empty string. So that `.Where(item=>!string.IsNullOrEmpty(item))` selects all the strings in the array except the ones that are empty,as you dont want them in the final result. It may be not necessary as finally you use a `String.Concat`, but i thought it would be cleaner in case you wanted the array anyway @EmirhanÖZKAN – Pikoh Sep 12 '17 at 14:35
  • @EmirhanÖZKAN so if you finally need just the string, you can remove that `Where` clause and the result would be the same – Pikoh Sep 12 '17 at 14:37
-1

Expanding on my comment before any answers were posted:

Problem: you're building a string by adding together a bunch of strings with +. A string is a collection of characters, so when you OrderBy you are actually shuffling the characters. (via C# interactive console):

( "ab" + "cd" + "ef" + "gh" + "ij").OrderBy(x => Guid.NewGuid())

> OrderedEnumerable<char, Guid> { 'c', 'i', 'e', 'd', 'a', 'f', 'h', 'b', 'g', 'j' }

Solution: Instead you need to define a collection of strings to shuffle:

var ans = new List<string>();
ans.Add("ab");
ans.Add("cd");
ans.Add("ef");
ans.Add("gh");
ans.Add("ij");

qAnswers = String.Join("", ans.OrderBy(x => Guid.NewGuid()))

> "cdijefghab"
BurnsBA
  • 4,347
  • 27
  • 39
  • Never use guids as a source of randomness. They are guaranteed to be *unique*, not *random*. – Eric Lippert Sep 12 '17 at 15:56
  • @EricLippert we've had this exact discussion before: https://codereview.stackexchange.com/q/164919/140484 . For quick shuffling, choosing between `Random` and a `NewGuid()` should be arbitrary, and on current windows OS, `NewGuid()` actually uses a CSPRNG unlike `Random`. If randomness is a critical feature of the app, then neither `Random` or `Guid.NewGuid()` is appropriate. – BurnsBA Sep 12 '17 at 17:17