用节填充UITableView

时间:2018-07-06 20:23:44

标签: arrays swift uitableview dictionary

我正在尝试用部分填充TableView。下面列出了一位歌手,该歌手是乐段名称,该歌手的所有歌曲都在下面列出。总计超过100位艺术家。像这样

FirstArtist
- Song 1
- Song 2

SecondArtist
 - Song 1
 - Song 2

OneMoreArtist...

我有一个对象数组Song

struct Song {

  let songName: String?
  let album: String?
  let artist: String?

}

var songs = [Song]()

以及所有艺术家姓名的数组

var artists = [String]()

据我所知,要用部分填充tableView,我需要一个Dictionary,以Artist作为键,并将Songs数组作为值,

var toShow = [String : [Song]]()

所以,然后我要循环播放

    for artist in artists {
      for song in songs {
        if song.artist == artist {

          toShow[artist] = [song]

//          toShow[artist]?.append(song)

        }
      }
    }

但这不起作用。

可能我走错了路。

在这种情况下有什么解决方案?

谢谢

更新

做出构图

    struct ArtistWithSongs  { 
       let name: String
       let songs: [Song]

        init(name: String, songs: [Song]) {
      self.name = name
      self.songs = songs
    }   
}

并尝试循环

var artistWithSongs = [ArtistWithSongs]() 

     for artist in artists {
          for song in songs {
            if artist == song.artist {
              artistWithSongs.append(ArtistWithSongs(name: song, songs: [song]))
            }
          }
        }

但是显然,我的循环变体是不正确的。现在,我得到了一个包含重复键的对象数组,每个键仅包含一首歌曲。看起来像

[Atrist1 : [Song1], Artist1 : [Song2], Artist1 : [Song3], ...]

我的问题是-进行循环的正确方法是什么,或者有可能以某种方式在Dictionary中合并具有相同键的对象以获得此[Artist1 :[Song1, Song2, Song3]]

3 个答案:

答案 0 :(得分:2)

感谢大家,我找到了一个解决方案here,它可以解决我想要达到的目标。大概是这样

let toShow = artistWithSongs.reduce([ArtistWithSongs](), { partialResult, artist in

    var dupe = partialResult.filter {$0.songName == group.name }.first
    if let dupeArtist = dupe {
        dupeArtist.songs?.append(contentsOf: artist.songs ?? [])
        return partialResult
    } else {
        var newPartialResult = partialResult
        newPartialResult.append(group)
        return newPartialResult
    }
})

答案 1 :(得分:1)

除了您的#ifndef NAMESPACE_IN_NAMESPACE #error "NAMESPACE_IN_NAMESPACE not defined" #endif } #undef NAMESPACE_NAME #undef NAMESPACE_NAME_STRING #undef NAMESPACE_IN_NAMESPACE 结构

Song

创建一个struct Song { let songName: String? let album: String? } 喜欢的人

Artist

然后创建一个数组

struct Artist { 
   let name:String
   let songs = [Song]()
}

var artists = [Artist]() let s1 = Song(songName:"name1",album:"alb1") let s2 = Song(songName:"name2",album:"alb2") let artist1 = Artist(name:"art",songs:[s1,s2]) artists.append(artist1) 中返回

numberOfSections

artists.count 中返回

numberOfRows

artists[section].songs.count 访问中

cellForRowAt

答案 2 :(得分:1)

如果要将歌曲([Song])的数组转换为字典([String : [Song]]),我建议使用函数式:

self.toShow = songs.reduce([String: [Song]]()) { acc, next in
  // mutable copy
  var acc = acc

  // since artist is optional we need to substitute it with non-optional value if it's nil
  let artist = next.artist ?? "Unknown Artist"

  // if dictionary already has this artist, then append the `next` song to an array
  if acc[artist] != nil {
    acc[artist]?.append(next)
  } else {
  // otherwise create new array
    acc[artist] = [next]
  }

  return acc
}

在表格的数据源中提供节数:

func numberOfSections(in tableView: UITableView) -> Int {
  return self.toShow.keys.count
}

然后您会遇到麻烦:对于部分中的行数,您需要知道该部分代表的艺术家。因此,我建议您再使用一种结构,即一组艺术家,以使各个部分的顺序保持一致:

self.artists = Array(self.toShow.keys).sorted()

这样,您可以为表提供以下数量的节和行:

func numberOfSections(in tableView: UITableView) -> Int {
  return self.artists.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  let artist = self.artists[section] // get the artist's name
  return self.toShow[artist]?.count ?? 0
}