我谈到了一个API,它给了我java.util.Iterator一个集合.这意味着我可以迭代它,但我不能直接/随机访问元素.
现在我的问题:我想从这个集合中获得一个随机元素.我怎么做?我想我可以构建一个允许直接访问的新集合,但这不是一点消耗内存吗?我也可以迭代整个集合,并为每个元素"掷骰子",看看我是否应该采用该元素并退出迭代或继续.但后来我需要集合的大小,我无法从迭代器中获得.
提前致谢.
Iterable<E>是在,java.lang而Iterator<E>在java.util.这有充分的理由还是仅仅是一个糟糕设计的神器?
这似乎很奇怪,因为唯一Iterable<E>有益的是提供一个Iterator<E>.
编辑:一个潜在的原因是因为(then-)新引入的每个循环.我想我的问题是,它们是否相同?
for(Object o : collection)
...
vs
for( Iterator iter = collection.iterator(); iter.hasNext(); ) {
o = iter.next();
...
Run Code Online (Sandbox Code Playgroud)
如果它们是,那么仍然无法解释为什么这两个类在不同的包中,因为编译器必须导入java.util才能使用该Iterator构造.
我编写了以下函数来比较两个迭代器,逐个元素.但是,如果我可以在标准库中重用某些东西,那就太好了.
fn iter_eq<A, B, T, U>(mut a: A, mut b: B) -> bool
where
A: Iterator<Item = T>,
B: Iterator<Item = U>,
T: PartialEq<U>,
{
loop {
match (a.next(), b.next()) {
(Some(ref a), Some(ref b)) if a == b => continue,
(None, None) => return true,
_ => return false,
}
}
}
fn main() {
let a = vec![1, 2, 3].into_iter();
let b = vec![1, 2, 3].into_iter();
assert!(iter_eq(a, b));
}
Run Code Online (Sandbox Code Playgroud) 在我的开发中,我正在慢慢地从面向对象的方法转向基于接口的编程方法.更确切地说:
一个简单的例子澄清了这一点.
过去我写过这些课程:
现在我写这些类:
这种方法允许我轻松地为每个接口实现模拟类,并在旧的,较慢的实现和新的,更快的实现之间切换,并在同一个应用程序中进行比较.
对于大多数情况,这非常好,但如果我想使用迭代器来循环集合,它就会成为一个问题.
假设我的图书馆有一系列书籍,我想对它们进行迭代.在过去,这不是问题:Library :: begin()和Library :: end()返回一个迭代器(Library :: iterator),我可以在其上轻松编写循环,如下所示:
for (Library::iterator it=myLibrary.begin();it!=mylibrary.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
问题是在基于接口的方法中,不能保证ILibrary的不同实现使用相同类型的迭代器.如果例如OldLibrary和NewLibrary都继承自ILibrary,那么:
要求两个ILibrary实现都返回相同类型的迭代器也不是解决方案,因为在实践中,增量操作(++ it)需要在两个实现中以不同方式实现.
这意味着在实践中我必须使迭代器成为一个接口,这意味着应用程序不能将迭代器放在堆栈上(典型的C++切片问题).
我可以通过在非接口类中包装iterator接口来解决这个问题,但对于我尝试obtian的东西,这似乎是一个非常复杂的解决方案.
有没有更好的方法来处理这个问题?
编辑: 马丁发表评论后的一些澄清.
假设我有一个类,它返回按受欢迎程度排序的所有书籍:LibraryBookFinder.它有begin()和end()方法,它们返回一个引用书籍的LibraryBookFinder :: const_iterator.
要用一个全新的实现替换旧的实现,我想将旧的LibraryBookFinder放在ILibraryBookFinder接口后面,并将旧实现重命名为OldSlowLibraryBookFinder.
然后我的名为VeryFastCachingLibraryBookFinder的新(快速快速)实现可以继承ILibraryBookFinder.这是迭代器问题的来源.
下一步可能是隐藏工厂后面的界面,在那里我可以要求工厂"给我一个'发现者'非常擅长根据人气,或根据标题,或作者,...返回书籍.你最终得到了像这样的代码:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_POPULARITY);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
或者如果我想使用其他标准:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_AUTHOR);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
LibraryBookFinderFactory的参数可以由外部因素决定:配置设置,命令行选项,对话框中的选择,......每个实现都有自己的优化(例如,书籍的作者不会改变)所以这可以是一个非常静态的缓存;流行度可以每天改变,这可能意味着完全不同的数据结构).
C++要求OutputIterator类型X支持表单的表达式r++,其中r是一个实例X.此后缀增量必须在语义上等效于:
(*) { X tmp = r; ++r; return tmp; }
并且必须返回可转换为的类型X const&.在C++ 11中,请参见24.2.4(但这不是新的).它说,在同一部分
输出迭代器上的算法绝不应该尝试两次通过相同的迭代器.它们应该是单通道算法.
给出(*),上面说我复制返回值就像 X a(r++);
假设r在递增之前是dereferencable,但没有取消引用.它是否需要a被取消参考?如果是这样,必须X a(r++); *a = t;执行相同的任务*r++ = t;吗?是否有任何(其他)条件a和r?
否则,假设r在递增之前被解除引用/分配,并且其递增的值(也)是不可引用的.以下哪一项(如果有的话)定义明确:(a)
*a = t;,(b)++a; *a = t;,(c)*r = t;?
另请参阅后续操作:取消引用 - 分配给双倍增量的OutputIterator
我正在创建一些函数来做一些事情,比如负数和正数的分离和,kahan,成对和其他东西,其中我从矩阵中获取元素的顺序无关紧要,例如:
template <typename T, int R, int C>
inline T sum(const Eigen::Matrix<T,R,C>& xs)
{
T sumP(0);
T sumN(0);
for (size_t i = 0, nRows = xs.rows(), nCols = xs.cols(); i < nRows; ++i)
for (size_t j = 0; j < nCols; ++j)
{
if (xs(i,j)>0)
sumP += xs(i,j);
else if (xs(i,j)<0) //ignore 0 elements: improvement for sparse matrices I think
sumN += xs(i,j);
}
return sumP+sumN;
}
Run Code Online (Sandbox Code Playgroud)
现在,我想尽可能提高效率,所以我的问题是,如上所述循环遍历每一行的每一列会更好,或者像下面这样做相反:
for (size_t i = 0, nRows = xs.rows(), nCols = xs.cols(); i …Run Code Online (Sandbox Code Playgroud) 我喜欢一致性.我最近问过使用std::begin与例如的问题std::vector<int>::begin,并且一致的决定似乎是使用前者,因为它更通用.但我想我在泥里找到了一根棍子.有时候,你想传达的是,当你循环通过时,你不会改变容器,因此调用std::vector<int>::cbegin.它将使你有时做你的代码很不对称iter = v.cbegin()等次做iter = begin(v).有没有办法解决这种缺乏对称性的问题,你还会推荐std::begin这种知识吗?为什么C++没有std::cbegin?
我可以显示如下目录列表:
use std::fs;
fn main() {
let paths = fs::read_dir("./").unwrap();
for path in paths {
println!("Name: {}", path.unwrap().path().display())
}
}
Run Code Online (Sandbox Code Playgroud)
我可以在ReadDir迭代之前对迭代器进行排序吗?目录名称是类似日期的数字201610131503.我阅读了文档,ReadDir但是没有找到内置函数.也许我不知道如何搜索?
考虑以下程序:
struct list_wrapper
{
std::vector<int> m_list;
};
int main()
{
std::vector<int> myList { 1, 1, 2, 3, 5 };
const std::vector<int>::iterator iter = myList.begin();
list_wrapper wrappedList;
wrappedList.m_list = std::move(myList);
// Can I still dereference iter?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在调用之后std::move(myList),iter现在指向内部的有效项wrappedList.m_list,或者移动构造函数/赋值使所有迭代器无效?
当从C++ 11的开头迭代std::vector到第二个到最后一个元素时,首选的样式是什么?
std::vector<const char*> argv;
std::string str;
Run Code Online (Sandbox Code Playgroud)
应该使用这种更多的C++ - esque方法
for (const auto& s: decltype(argv)(argv.begin(), argv.end()-1)) {
str += std::string(s) + ' ';
}
Run Code Online (Sandbox Code Playgroud)
还是应该采用更传统的方式?
for (size_t i = 0; i < argv.size() - 1; ++i) {
str += std::string(argv[i]);
}
Run Code Online (Sandbox Code Playgroud)