jjzjj

在自定义 Array2D 类上枚举的 Swift for-in 循环?

coder 2023-09-16 原文

我将如何实现一个自定义枚举函数来实现这样的功能(Swift 2):

for ((column, row), item) in Array2D.enumerate() { ... }

在我简单的 Array2D 结构中:

struct Array2D<T> : SequenceType {
    let columns: Int
    let rows: Int
    private var array: Array<T?>

    init(columns: Int, rows: Int) {
        self.columns = columns
        self.rows = rows
        array = Array(count: rows*columns, repeatedValue: nil)
    }

    subscript(column: Int, row: Int) -> T? {
        get {
            return array[columns*row + column]
        }
        set {
            array[columns*row + column] = newValue
        }
    }

    func generate() -> AnyGenerator<T?> {
        var column = 0
        var row = 0

        return anyGenerator() {
            guard row < self.rows else {
                return nil
            }

            let item = self[column, row]

            if ++column == self.columns {
                column = 0
                ++row
            }

            return item
        }
    }
}

我找不到关于在 Swift 中实现枚举函数的任何好的解释

最佳答案

Swift 中的 enumerate() 函数为其元组的第一部分返回从 0 开始的整数。这些与您枚举的顺序无关。因此,例如,这是行不通的:

let word = "hello".characters

for (index, letter) in word.enumerate() {
  print(word[index])
}

因为 characterView 的索引是 String.Index

因此,有多种方法可以获得您想要的东西。第一种是为您的结构重载 enumerate()。同样,有几天你可以做到这一点。首先,使用您自己的生成器并使用自己的逻辑计算坐标的函数怎么样。这可能有效:

func enumerate() -> AnyGenerator<((Int, Int), T?)> {
  let g = self.generate()
  var coord = -1
  return anyGenerator {
    g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
  }
}

但是您在那里复制代码,尤其是从您的生成方法。看到您已经在使用坐标来返回每个元素,为什么不让您的枚举方法成为默认方法,并在其上调用您的生成方法。像这样:

// Original generate method, now returns the coords it used
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
  var column = 0
  var row = 0

  return anyGenerator() {
    guard row < self.rows else {
      return nil
    }

    let item = self[column, row]

    if ++column == self.columns {
      column = 0
      ++row
    }

    return ((column, row), item)
  }
}

// uses enumerate, ignores coords

func generate() -> AnyGenerator<T?> {
  let g = self.enumerate()
  return anyGenerator {
    g.next().map { $1 }
  }
}

如果您想走极端,您可以编写枚举函数来枚举其基数的特定 索引。将其命名为 specEnumerate:

public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {

  private var eG: Base.Generator
  private let sI: Base.Index
  private var i : Base.Index?

  public mutating func next() -> (Base.Index, Base.Generator.Element)? {
    i?._successorInPlace() ?? {self.i = self.sI}()
    return eG.next().map { (i!, $0) }
  }

  private init(g: Base.Generator, i: Base.Index) {
    self.eG = g
    self.sI = i
    self.i = nil
  }
}

public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {

  private let col: Base
  public func generate() -> SpecEnumerateGen<Base> {
    return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
  }
}

public extension CollectionType {
  func specEnumerate() -> SpecEnumerateSeq<Self> {
    return SpecEnumerateSeq(col: self)
  }
}

有了这个函数,这工作:

let word = "hello".characters

for (index, letter) in word.specEnumerate() {
  print(word[index])
}

但是您的矩阵结构仍然是 SequenceType,没有特定的索引。为此,您必须实现自己的 MatrixIndex:

public struct MatrixIndex: BidirectionalIndexType {

  public let x, y : Int

  private let columns: Int

  public func successor() -> MatrixIndex {
    return (x + 1 == columns) ?
      MatrixIndex(x: 0, y: y + 1, columns: columns) :
      MatrixIndex(x: x + 1, y: y, columns: columns)
  }

  public func predecessor() -> MatrixIndex {
    return (x == 0) ?
      MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
      MatrixIndex(x: x - 1, y: y, columns: columns)
  }
}

public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
  return lhs.x == rhs.x && lhs.y == rhs.y
}

extension MatrixIndex : CustomDebugStringConvertible {
  public var debugDescription: String {
    return "\(x), \(y)"
  }
}

extension MatrixIndex: RandomAccessIndexType {
  public func advancedBy(n: Int) -> MatrixIndex {
    let total = (y * columns) + x + n
    return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
  }
  public func distanceTo(other: MatrixIndex) -> Int {
    return (other.x - x) + (other.y - y) * columns
  }
}

没错。现在你需要另一个矩阵结构:

public struct Matrix2D<T> : MutableCollectionType {
  public var contents: [[T]]
  public subscript(index: MatrixIndex) -> T {
    get {
      return contents[index.y][index.x]
    } set {
      self.contents[index.y][index.x] = newValue
    }
  }
  public var count: Int { return contents[0].count * contents.count }
  public var startIndex: MatrixIndex {
    return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
  }
  public var endIndex: MatrixIndex {
    return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
  }
}

没错。所以现在,在所有这些之后,这有效:

let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])

for (coordinate, value) in myMatrix.specEnumerate() {
  value == myMatrix[coordinate] // True every time
}

关于在自定义 Array2D 类上枚举的 Swift for-in 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31386142/

有关在自定义 Array2D 类上枚举的 Swift for-in 循环?的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

    我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby-on-rails - Rails 3 I18 : translation missing: da. datetime.distance_in_words.about_x_hours - 2

    我看到这个错误:translationmissing:da.datetime.distance_in_words.about_x_hours我的语言环境文件:http://pastie.org/2944890我的看法:我已将其添加到我的application.rb中:config.i18n.load_path+=Dir[Rails.root.join('my','locales','*.{rb,yml}').to_s]config.i18n.default_locale=:da如果我删除I18配置,帮助程序会处理英语。更新:我在config/enviorments/devolpment

  5. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  8. arrays - 这是 Ruby 中 Array.fill 方法的错误吗? - 2

    这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]

  9. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  10. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

随机推荐