如何通过IEnumerable访问foreach迭代中的下一个和上一个项目?

时间:2019-04-02 12:02:46

标签: c# foreach ienumerable

我想在处理当前项目并遍历IEnumerable<object>时访问下一个和上一个项目(如果在范围内),据我所知,该List<object>没有索引器。

尽管我现在唯一知道这是唯一的选择,但我并不需要一个public static void PrintTokens(IEnumerable<object> tokens) { foreach (var token in tokens) { // var next = ? // var prev = ? } } 集合或一个数组来完成此操作。

如果可能的话,我也希望避免使用Linq表达式。

这就是我当前方法的定义方式:

import UIKit

struct User: Codable {
let firstName: String
let lastName: String
let email: String
let userid: String

enum CodingKeys: String, CodingKey {
    case firstName = "first_name"
    case lastName = "last_name"
    case email = "email"
    case userid = "user_id"
}
}

class tableViewCellLabels: UITableViewCell {

@IBOutlet var lbl_firstName: UILabel!
@IBOutlet var lbl_lastName: UILabel!
@IBOutlet var lbl_email: UILabel!
@IBOutlet var lbl_userid: UILabel!

}

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableview1: UITableView!
@IBOutlet var tableview2: UITableView!
private var dataSource = [User]() {
    didSet {
        self.tableview1.reloadData()
    }
}


override func viewDidLoad() {
    super.viewDidLoad()

    self.tableview1.dataSource = self
    self.tableview1.delegate = self

    let url = URL(string: "https://test.netperformers.de/users")

    URLSession.shared.dataTask(with: url!, completionHandler: { [weak self] (data, response, error) in
        guard let data = data, error == nil else {
            print(error?.localizedDescription ?? "An error occurred")
            return
        }

        DispatchQueue.main.async {
            self?.dataSource = try! JSONDecoder().decode([User].self, from: data)
        }
    }).resume()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    tableview1.reloadData()
}

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dataSource.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if tableView == tableView{
        print(dataSource[indexPath.row]) // your clicked user data
    }else{
        // Second Tableview Click Event here
    }

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath) as! tableViewCellLabels
    let user = self.dataSource[indexPath.row]

    cell.lbl_firstName.text = user.firstName
    cell.lbl_lastName.text = user.lastName
    cell.lbl_userid.text = user.userid
    return cell
}
func tableView1(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if tableView == tableView{
        print(dataSource[indexPath.row]) // your clicked user data
    }else{
        // Second Tableview Click Event here
    }

}
}

5 个答案:

答案 0 :(得分:3)

您可以像往常一样进行循环,但是您当前使用的项目变为next,上一个项目为current,而之前的项目为prev

object prev = null;
object current = null;
bool first = true;
foreach (var next in tokens)
{
    if (!first)
    {
        Console.WriteLine("Processing {0}. Prev = {1}. Next = {2}", current, prev, next);
    }

    prev = current;
    current = next;
    first = false;
}

// Process the final item (if there is one)
if (!first)
{
    Console.WriteLine("Processing {0}. Prev = {1}. Next = {2}", current, prev, null);
}

如果您使用的是C#7.0+,则可以编写

(prev, current, first) = (current, next, false);

而不是循环结束时的三个独立语句。

答案 1 :(得分:1)

我写了一个扩展方法,该方法返回一个包含三个对象的元组:上一个,当前和下一个:

public static class Extensions
{
    public static IEnumerable<Tuple<T, T, T>> GetItems<T>(this IEnumerable<T> source)
        where T : class
    {
        if (source != null)
        {
            // skip the first iteration to be able to include next item
            bool skip = true;
            T previous = default(T), current = default(T), next = default(T);
            foreach (T item in source)
            {
                next = item;
                if (!skip)
                {
                    yield return new Tuple<T, T, T>(previous, current, next);
                }
                previous = current;
                current = item;
                skip = false;
            }
            if (!skip)
            {
                next = default(T);
                yield return new Tuple<T, T, T>(previous, current, next);
            }
        }
    }
}

希望有帮助。也许使用自定义类而不是元组进行扩展。

答案 2 :(得分:0)

U可以尝试这种扩展方法。它是“大小”上一个项目,“大小”下一个项目和当前项目:

    public static System.Collections.Generic.IEnumerable<TResult> Select<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource> source, int size, System.Func<Queue<TSource>, TSource, Queue<TSource>, TResult> selector)
    {
        if (source == null)
        {
            throw new System.ArgumentNullException("source");
        }

        if (selector == null)
        {
            throw new System.ArgumentNullException("selector");
        }
        Queue<TSource> prevQueue = new Queue<TSource>(size);
        Queue<TSource> nextQueue = new Queue<TSource>(size);

        int i = 0;
        foreach (TSource item in source)
        {
            nextQueue.Enqueue(item);
            if (i++ >= size)
            {
                TSource it = nextQueue.Dequeue();
                yield return selector(prevQueue, it, nextQueue);
                prevQueue.Enqueue(it);
                if (prevQueue.Count > size)
                {
                    prevQueue.Dequeue();
                }
            }
        }

        while (nextQueue.Any())
        {
            TSource it = nextQueue.Dequeue();
            yield return selector(prevQueue, it, nextQueue);
            prevQueue.Enqueue(it);
            if (prevQueue.Count > size)
            {
                prevQueue.Dequeue();
            }
        }
    }

答案 3 :(得分:-1)

我认为原始的IEnumerable不能提供,但是LinkedList可以提供。

答案 4 :(得分:-1)

摘自文档:

  

IEnumerable公开了一个枚举器,该枚举器支持简单的迭代

因此,要实现所需的目标,可以采用以下四种方法之一:

  • 在令牌变量上调用ToList()-这样,您可以按索引访问项目
  • 在IEnumerable上使用ElementAt()方法,但是它会缺乏性能,因为每次调用此方法时都会枚举令牌
  • 按照您的建议,将IEnumerable<object> tokens更改为IList<object> tokens
  • 编写自定义循环,保存上一个,当前和下一个项目(下一个实际上是循环中的当前项目)