C#功能问题我不明白为什么 [英] C# Function Problem I Dont Understand Why

查看:63
本文介绍了C#功能问题我不明白为什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上对于从1到20的循环我需要通过ID从1-20给用户不同的随机问题,现在这里是问题,基本上在开始我创建一个AskedQuestions字典变量< int,bool>并且我正在创建一个循环,将所有值从密钥1-20设置为false,



获取随机数的函数在这里。



  public   int  GetRandomNumber( )
{
Random rnd = new Random();
int returnpoint = _rnd.Next( 1 ,_ itemLength + 1);
if (AskedQuestions [returnpoint] == true )GetRandomNumber();
AskedQuestions [returnpoint] = true ;
return returnpoint;
}
public void AskQuestion( int QuestionID)
{
// 从databaza中读取问题questionID
}





就在这里我使用这样的命令... AskQuestion(GetRandomNumber()) ;

但是我不明白为什么有些问题会被多次显示?我所制作的代码,它应该不会出现这个问题...你怎么看? ?!



i希望你在这里理解我的问题,如果没有..问我,我会回复更多信息.. tnx提前...

解决方案

0)使Random成为类的静态成员。

1)请不要使用递归来执行此操作。

2)这是一个糟糕的算法。

最重要的是......

3)更改

if(一个skedQuestions [returnpoint] == true)GetRandomNumber();

to

if(AskedQuestions [returnpoint] == true) returnpoint = GetRandomNumber();



if(AskedQuestions [returnpoint] ] == true)返回 GetRandomNumber();



但是,严肃地说,使用更好的算法。



这里,主要使用你自己的代码,仍然是一个糟糕的算法,但没有递归:



  private   static 随机rnd =  new  Random(); 
public int GetRandomNumber()
{
int returnpoint;
do
{
returnpoint = _rnd.Next( 1 , _questionLength + 1);
}
while (AskedQuestions [returnpoint]);
AskedQuestions [returnpoint] = true ;
return returnpoint;
}


多次询问某些问题的原因是由于代码处理已经提出随机选择的问题的情况的方式之前。



第一次考虑(以前没有问过任何问题),让我们说问题5是随机选择的。 if语句将为false并将问题5标记为已被询问并将返回数字5.到目前为止这么好。



但是,一段时间之后,Random.Next可能会再次返回5。这次if语句是真的,你递归地寻找另一个数字(如果你很幸运)。假设这个对GetRandomNumber的调用返回,比方说,值为8.但是这个值被丢弃,原始函数调用继续返回值5(这是一个已经被问到的问题编号)。



您可能想要考虑在用完问题时会发生什么?



或许更好的方法是建立问题编号列表,然后在使用它们时,将它们从列表中删除,直到列表为空。



使用System; 
使用System.Collections.Generic;

namespace TwentyQuestions
{
public class Quiz
{
private const int NUM_QUESTIONS = 20;
private List< int> UnaskedQuestions = new List< int>();
private Random _rnd = new Random();

public Quiz()
{
for(int i = 0; i< NUM_QUESTIONS; i ++)
UnaskedQuestions.Add(i + 1);
}

public void Run()
{
try
{
while(true)
AskQuestion(GetRandomNumber() );
}
catch(ApplicationException Ex)
{
Console.WriteLine(Ex.Message);
}
}

public int GetRandomNumber()
{
if(UnaskedQuestions.Count == 0)
抛出新的ApplicationException(别再问问题了);
int returnpoint = _rnd.Next(UnaskedQuestions.Count);
int questionNumber = UnaskedQuestions [returnpoint];
UnaskedQuestions.RemoveAt(returnpoint);
返回questionNumber;
}

public void AskQuestion(int QuestionID)
{
Console.Write(Answer question+ QuestionID.ToString()+
(或空白退出)?);
string answer = Console.ReadLine();
if(String.IsNullOrEmpty(answer))
抛出新的ApplicationException(空白答案);
}
}
}


使用一点Linq我们可以简化这一点,并使其灵活:< pre lang =c#> 使用系统;
使用 System.Collections.Generic;
使用 System.Linq;
使用 System.Windows.Forms;

private const int NumberOfAvailableQuestions = 100 ;

private const int NumberOfQuestions = 20 ;

私人字典< int,bool> TestResults = new Dictionary< int,bool>();

private List< string> AvailableQuestions = new List< string>(NumberOfAvailableQuestions);

private List< string> currentQuestionList = new List< string>(NumberOfQuestions);

private 随机getRand = new Random(DateTime.Now.Millisecond);

// 用于测试
private void mockInitializeQuestions()
{
for int i = 0 ; i < NumberOfAvailableQuestions; i ++)
{
AvailableQuestions.Add( string .Format( 问题#{0},i + 1 ));
}
}

私有 void mockStartTest( )
{
// initialize
if (AvailableQuestions == null )mockInitializeQuestions();

TestResults.Clear();
currentQuestionList.Clear();

// 复制可用的问题
string [] copiedQuestions = new string [NumberOfAvailableQuestions];
AvailableQuestions.CopyTo(copiedQuestions);

// 随机排序所有问题的复制列表
// 并获取它们的第一个#NumberOfQuestions
currentQuestionList = copiedQuestions.OrderBy(q = > getRand.Next( 0 ,NumberOfAvailableQuestions))。ToList()。GetRange( 0 ,NumberOfQuestions);

// 开始测试
foreach string question in currentQuestionList)
{
// 显示问题,得到答案
// 更新TestResults字典

// 仅用于测试
Console.WriteLine(question);
}
}

要问的好问题:



1.为什么要复制所有可用的问题?因为我已经做出了假设/猜测所有问题的原始列表应该按顺序保存,这是有充分理由的。



2.不是吗浪费复制所有这些字符串?不:'CopyTo执行浅拷贝。



3.如果您声称'CopyTo执行仅参考副本(浅),则不对复制排序原始列表?没有。



我猜想将来什么是现在'字符串将被<替换为某些类的实例,其中包含用多选答案之类的问题提出问题所需的其他数据:在这种情况下,任何复制的成本都是最小的,因为它只是复制的引用。


basically for loop from 1 to 20 i need to give the user different random questions by ID from 1-20, now here is the problem, basically on start i create a "AskedQuestions "dictionary variable <int,bool> and im making a loop that will set all the values from key 1-20 to false,

the function that gets random number is here.

public int GetRandomNumber()
        {
            Random rnd = new Random();
            int returnpoint = _rnd.Next(1, _questionLength+1);
            if (AskedQuestions[returnpoint] == true) GetRandomNumber();
            AskedQuestions[returnpoint] = true;
            return returnpoint;
        }
public void AskQuestion(int QuestionID)
        {
            //read the question from databaza with the questionID
        }



right here im using the commands like this... AskQuestion(GetRandomNumber());
but i dont understand why some questions are shown multiple times? by the code i made, it shouldn't do that problem... what do you think .. ?!

i hope you understand my problem here, if not .. ask me i will reply for additional info.. tnx in advance...

解决方案

0) Make the Random a static member of the class.
1) Please don't use recursion to do this.
2) That's a poor algorithm.
Most of all...
3) Change
if (AskedQuestions[returnpoint] == true) GetRandomNumber();
to
if (AskedQuestions[returnpoint] == true) returnpoint= GetRandomNumber();
or
if (AskedQuestions[returnpoint] == true) return GetRandomNumber();

But, seriously, use a better algorithm.

Here, using mostly your own code, still a bad algorithm, but without recursion:

private static Random rnd = new Random();
public int GetRandomNumber()
        {
            int returnpoint ;
            do
            {
              returnpoint = _rnd.Next(1, _questionLength+1);
            }
            while (AskedQuestions[returnpoint]);
            AskedQuestions[returnpoint] = true;
            return returnpoint;
        }


The reason that some questions are asked multiple times is due to the way the code handles the case where a randomly selected question has been asked before.

Consider on the first time through (when no questions have been asked before), let's say Question 5 is randomly selected. The if statement will be false and will mark Question 5 as 'has been asked' and will return the number 5. So far so good.

However, some time later, Random.Next might return 5 again. This time the if statement is true and you recursively seek another number (if you're lucky). Let's say that this call to GetRandomNumber returns, let's say, the value 8. However this value is discarded and the original function call proceeds to return the value 5 (which is an already asked question number).

You might want to consider what happens when you run out of questions?

Perhaps a better approach is to build a list of question numbers, and then as they are used, remove them from the list, until the list is empty.

using System;
using System.Collections.Generic;

namespace TwentyQuestions
{
    public class Quiz
    {
        private const int NUM_QUESTIONS = 20;
        private List<int> UnaskedQuestions = new List<int>();
        private Random _rnd = new Random();

        public Quiz()
        {
            for (int i = 0; i < NUM_QUESTIONS; i++)
                UnaskedQuestions.Add(i+1);
        }

        public void Run()
        {
            try
            {
                while (true)                
                    AskQuestion(GetRandomNumber());                                        
            }
            catch (ApplicationException Ex)
            {
                Console.WriteLine(Ex.Message);
            }
        }

        public int GetRandomNumber()
        {
            if (UnaskedQuestions.Count == 0) 
                throw new ApplicationException("No more questions");
            int returnpoint = _rnd.Next(UnaskedQuestions.Count);
            int questionNumber = UnaskedQuestions[returnpoint];
            UnaskedQuestions.RemoveAt(returnpoint);
            return questionNumber;
        }       

        public void AskQuestion(int QuestionID)
        {
            Console.Write("Answer question " + QuestionID.ToString() + 
                " (or blank to exit)? ");
            string answer = Console.ReadLine();
            if (String.IsNullOrEmpty(answer)) 
                throw new ApplicationException("Blank answer");
        }
    }
}


Using a little Linq we can simplify this, and make it "flexible:"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

private const int NumberOfAvailableQuestions = 100;

private const int NumberOfQuestions = 20;

private Dictionary<int,bool> TestResults = new Dictionary<int,bool>(); 

private List<string> AvailableQuestions = new List<string>(NumberOfAvailableQuestions);

private List<string> currentQuestionList = new List<string>(NumberOfQuestions); 

private Random getRand = new Random(DateTime.Now.Millisecond);

// for testing
private void mockInitializeQuestions()
{
    for (int i = 0; i < NumberOfAvailableQuestions; i++)
    {
        AvailableQuestions.Add(string.Format("question #{0}", i + 1));
    } 
}

private void mockStartTest()
{
    // initialize
    if(AvailableQuestions == null) mockInitializeQuestions();

    TestResults.Clear();
    currentQuestionList.Clear();

    // copy the available questions
    string[] copiedQuestions = new string[NumberOfAvailableQuestions];
    AvailableQuestions.CopyTo(copiedQuestions);

    // random sort the copied list of all questions
    // and take the first #NumberOfQuestions of them
    currentQuestionList = copiedQuestions.OrderBy(q => getRand.Next(0, NumberOfAvailableQuestions)).ToList().GetRange(0, NumberOfQuestions);

    // start the test
    foreach (string question in currentQuestionList)
    {
        // show the question, get an answer
        // update the TestResults Dictionary

        // for testing only
        Console.WriteLine(question);
    }
}

Good questions to ask:

1. why do you copy all the available questions ? because I have made the assumption/guess that the "original" list of all questions should be kept in order-created for good reason.

2. isn't it wasteful to copy all those strings ? no: 'CopyTo performs a "shallow copy."

3. if you claim that 'CopyTo performs a reference-only copy (shallow) then doesn't sorting the copy sort the original list ? no.

I would guess that in the future what are now the 'strings will be replaced by instances of some Class that will contain other data needed to present a question with things like "multiple choice" answers: when that's the case then the cost any copying will be minimal since it's just references copied.


这篇关于C#功能问题我不明白为什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆