我想知道为什么我改变了行
import Tweet, pickle
timeline = []
save_tweets = 'tweets.dat'
def main():
while True:
tweet_menu()
choice = get_choice()
if choice==1:
make_tweet()
elif choice==2:
view_tweets()
elif choice==3:
search_tweets()
elif choice==4:
print('Thank you for using Tweet Manager.')
break
def tweet_menu():
print(' ')
print('Tweet Menu')
print('_____________')
print('1. Make a tweet')
print('2. View recent tweets')
print('3. Search tweets')
print('4. Quit')
def get_choice():
while True:
try:
choice = int(input('Which would you like to do? '))
if choice < 1 or choice > 4:
print('That is not a valid choice.')
continue
except:
print('Please enter a number between 1 and 4.')
else:
break
return choice
def make_tweet():
author = input('What is your name? ')
while True:
text = input('What would you like to tweet? ')
if len(text) > 140:
print('Error: Tweets cannot be longer than 140 characters.')
continue
else:
break
age = 0
#Create a tweet object.
tweet = Tweet.Tweet(author,text,age)
#Add the tweet to the list.
timeline.append(tweet)
#Encrypt the tweets to a data file.
try:
save_tweets = open('tweets.dat', 'wb')
pickle.dump(timeline, save_tweets)
save_tweets.close()
except:
print('Your tweets could not be saved.')
print('Your tweet has been saved.')
def view_tweets():
#Unpickle the tweets so the user can access them.
try:
load_file = open(save_tweets, 'rb')
timeline = pickle.load(load_file)
load_file.close()
except:
print('The tweets could not be loaded.')
print('Recent Tweets')
print('______________')
if len(timeline) == 0:
print('There are no recent tweets.')
for tweet in timeline[-5]:
print(timeline.get_author, '-', timeline.get_age)
print(timeline.get_text)
def search_tweets():
match = 0
timeline.reverse()
if timeline ==[]:
print('There are no tweets to search at this time.')
search = input('What would you like to search for? ')
for tweet in timeline:
if (search in timeline.get_text):
match = 1
if match == 1:
print('Search Results')
print('_______________')
print(tweet.Tweet.get_author, '-', tweet.Tweet.get_age)
print(tweet.Tweet.get_text)
else:
print('Search Results')
print('_______________')
print('No tweets contained ', tweet.Tweet.get_author,
tweet.Tweet.get_text)
main()
到
"sub = sub.SelectMany(x => x.Next(i)).ToList();"
我收到错误
第48行:System.IndexOutOfRangeException:当我向方法SolveNQueens提供4的输入时,索引超出了数组的范围。
我认为这可能与懒惰评估有关。
下面列出了完整的代码示例,它是一种有效的解决方案 对于女王问题。
"sub = sub.SelectMany(x => x.Next(i));"
答案 0 :(得分:3)
失败的原因是因为for loop
中使用的迭代器变量在captured by a closure时被评估的方式。当您删除循环内的ToList()
时,sub
IEnumerable
仅在返回语句sub
中实现return sub.Select(x => x.ToPosition()).ToList();
时进行评估。此时,for循环变量i
的值为n(例如标准棋盘上为8),它位于数组范围之外。
但是,当您立即实现List
时,不会遇到副作用,因为i
的值在下一次迭代之前使用(ToList
具体化)。
使用:
for (int i = 0; i < n; i++)
{
// Materialized here so `i` evaluated immediately
sub = sub.SelectMany(x => x.Next(i)).ToList();
}
断裂:
for (int i = 0; i < n; i++)
{
sub = sub.SelectMany(x => x.Next(i));
}
return sub.Select(x => x.ToPosition()).ToList(); // `i` evaluated here
要fix
for循环变量评估问题,您可以显式捕获迭代器变量的当前值:
for (int i = 0; i < n; i++)
{
var loop = i;
sub = sub.SelectMany(x => x.Next(loop)); // No To List - lazy evaluation
}
Re:在FP范例代码中避免循环
OP的SolveNQueens
方法使用循环逐步更改sub
,而不是递归,但for也可以替换为foreach和范围:
foreach(var i in Enumerable.Range(0, n))
{
sub = sub.SelectMany(x => x.Next(i));
}
然后哪个Resharper重写为左折:
sub = Enumerable.Range(0, n)
.Aggregate(sub, (current, i) => current.SelectMany(x => x.Next(i)));
无论哪种方式,都避免了在for
循环内对延迟评估迭代器变量的缺陷。