我有一个包含Post
个对象的数组。每个Post
都有一个id
属性。
是否有更有效的方法可以在我的数组中找到重复的帖子ID而不是
for post1 in posts {
for post2 in posts {
if post1.id == post2.id {
posts.removeObject(post2)
}
}
}
答案 0 :(得分:26)
我将建议2个解决方案。
这两种方法都需要Post
为Hashable
和Equatable
这里我假设您的Post
结构(或类)具有id
类型的String
属性。
struct Post: Hashable, Equatable {
let id: String
var hashValue: Int { get { return id.hashValue } }
}
func ==(left:Post, right:Post) -> Bool {
return left.id == right.id
}
要删除重复内容,您可以使用Set
let uniquePosts = Array(Set(posts))
var alreadyThere = Set<Post>()
let uniquePosts = posts.flatMap { (post) -> Post? in
guard !alreadyThere.contains(post) else { return nil }
alreadyThere.insert(post)
return post
}
答案 1 :(得分:3)
我的纯粹&#39;没有Post符合Hashable的Swift解决方案(Set需要)
struct Post {
var id: Int
}
let posts = [Post(id: 1),Post(id: 2),Post(id: 1),Post(id: 3),Post(id: 4),Post(id: 2)]
// (1)
var res:[Post] = []
posts.forEach { (p) -> () in
if !res.contains ({ $0.id == p.id }) {
res.append(p)
}
}
print(res) // [Post(id: 1), Post(id: 2), Post(id: 3), Post(id: 4)]
// (2)
let res2 = posts.reduce([]) { (var r, p) -> [Post] in
if !r.contains ({ $0.id == p.id }) {
r.append(p)
}
return r
}
print(res2) // [Post(id: 1), Post(id: 2), Post(id: 3), Post(id: 4)]
我更喜欢(1)封装成函数(又名func unique(posts:[Post])->[Post]
),也许是扩展数组....
答案 2 :(得分:3)
(针对Swift 3更新)
正如我在对该问题的评论中提到的,您可以在the thread we previously marked this post to be duplicate of中使用修改后的Daniel Kroms解决方案。只需使Post
对象可以缓存(通过id
属性隐式等同)并实现修改(使用Set
而不是Dictionary
;不使用链接方法中的dict值无论如何)Daniel Kroms uniq
的功能如下:
func uniq<S: Sequence, E: Hashable>(_ source: S) -> [E] where E == S.Iterator.Element {
var seen = Set<E>()
return source.filter { seen.update(with: $0) == nil }
}
struct Post : Hashable {
var id : Int
var hashValue : Int { return self.id }
}
func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
var posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)]
print(Posts)
/* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */
var myUniquePosts = uniq(posts)
print(myUniquePosts)
/* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)] */
这将删除重复项,同时保持原始数组的顺序。
辅助功能uniq
为Sequence
分机
除了使用免费功能外,我们还可以将uniq
实施为受约束的Sequence
扩展名:
extension Sequence where Iterator.Element: Hashable {
func uniq() -> [Iterator.Element] {
var seen = Set<Iterator.Element>()
return filter { seen.update(with: $0) == nil }
}
}
struct Post : Hashable {
var id : Int
var hashValue : Int { return self.id }
}
func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
var posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)]
print(posts)
/* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */
var myUniquePosts = posts.uniq()
print(myUniquePosts)
/* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)] */
答案 3 :(得分:2)
保留顺序,不添加额外状态:
func removeDuplicates<T: Equatable>(accumulator: [T], element: T) -> [T] {
return accumulator.contains(element) ?
accumulator :
accumulator + [element]
}
posts.reduce([], removeDuplicates)
答案 4 :(得分:2)
在swift 3中,请参阅以下代码:
onDestroy
答案 5 :(得分:1)
使用Set
要使用它,请使您的帖子可以播放并实施==
运算符
import Foundation
class Post: Hashable, Equatable {
let id:UInt
let title:String
let date:NSDate
var hashValue: Int { get{
return Int(self.id)
}
}
init(id:UInt, title:String, date:NSDate){
self.id = id
self.title = title
self.date = date
}
}
func ==(lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
let posts = [Post(id: 11, title: "sadf", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 1; c.year = 2016; return c}())!),
Post(id: 33, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!),
Post(id: 22, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!),
Post(id: 22, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!)]
从具有重复项的数组创建集
let postsSet = Set(posts)
这是无序的,创建一个新数组,应用订单。
let uniquePosts = Array(postsSet).sort { (p1, p2) -> Bool in
return p1.date.timeIntervalSince1970 < p2.date.timeIntervalSince1970
}
您也可以使用包装类,而不是使Post
模型可以使用。此包装类将使用post objects属性来计算哈希值和相等性
这个包装器可以通过闭包来配置:
class HashableWrapper<T>: Hashable {
let object: T
let equal: (obj1: T,obj2: T) -> Bool
let hash: (obj: T) -> Int
var hashValue:Int {
get {
return self.hash(obj: self.object)
}
}
init(obj: T, equal:(obj1: T, obj2: T) -> Bool, hash: (obj: T) -> Int) {
self.object = obj
self.equal = equal
self.hash = hash
}
}
func ==<T>(lhs:HashableWrapper<T>, rhs:HashableWrapper<T>) -> Bool
{
return lhs.equal(obj1: lhs.object,obj2: rhs.object)
}
The Post可能只是
class Post {
let id:UInt
let title:String
let date:NSDate
init(id:UInt, title:String, date:NSDate){
self.id = id
self.title = title
self.date = date
}
}
让我们像以前一样创建一些帖子
let posts = [
Post(id: 3, title: "sadf", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 1; c.year = 2016; return c}())!),
Post(id: 1, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!),
Post(id: 2, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!),
Post(id: 2, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!),
Post(id: 1, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!)
]
现在,我们使用闭包为每个帖子创建包装器对象,以确定相等性和哈希值。我们创建了这个集合。
let wrappers = posts.map { (p) -> HashableWrapper<Post> in
return HashableWrapper<Post>(obj: p, equal: { (obj1, obj2) -> Bool in
return obj1.id == obj2.id
}, hash: { (obj) -> Int in
return Int(obj.id)
})
}
let s = Set(wrappers)
现在我们提取包装的对象并按日期排序。
let objects = s.map { (w) -> Post in
return w.object
}.sort { (p1, p2) -> Bool in
return p1.date.timeIntervalSince1970 > p2.date.timeIntervalSince1970
}
和
print(objects.map{$0.id})
打印
[1, 3, 2]
答案 6 :(得分:1)
这也适用于多维数组:
for (index, element) in arr.enumerated().reversed() {
if arr.filter({ $0 == element}).count > 1 {
arr.remove(at: index)
}
}
答案 7 :(得分:1)
我在Swift 5上的解决方案:
添加扩展名:
public class MainActivity extends Activity {
private EditText e1;
private EditText e2;
private TextView tv4;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
e1 = (EditText) findViewById(R.id.et1);
e2 = (EditText) findViewById(R.id.et2);
tv4 = (TextView) findViewById(R.id.tv4);
}
Class Client,重要的是具有像Hashable这样的类:
extension Array where Element: Hashable {
func removingDuplicates<T: Hashable>(byKey key: (Element) -> T) -> [Element] {
var result = [Element]()
var seen = Set<T>()
for value in self {
if seen.insert(key(value)).inserted {
result.append(value)
}
}
return result
}
}
使用:
struct Client:Hashable {
let uid :String
let notifications:Bool
init(uid:String,dictionary:[String:Any]) {
self.uid = uid
self.notifications = dictionary["notificationsStatus"] as? Bool ?? false
}
static func == (lhs: Client, rhs: Client) -> Bool {
return lhs.uid == rhs.uid
}
}
有个美好的一天,快恋人♥️
答案 8 :(得分:1)
func removeDuplicateElements(post: [Post]) -> [Post] {
var uniquePosts = [Post]()
for post in posts {
if !uniquePosts.contains(where: {$0.postId == post.postId }) {
uniquePosts.append(post)
}
}
return uniquePosts
}
答案 9 :(得分:0)
您可以只使用一个集合,而不是使用可散列对象。获取要删除重复项的属性值,并将其用作测试值。在我的示例中,我正在检查重复的ISBN值。
do {
try fetchRequestController.performFetch()
print(fetchRequestController.fetchedObjects?.count)
var set = Set<String>()
for entry in fetchRequestController.fetchedObjects! {
if set.contains(entry.isbn!){
fetchRequestController.managedObjectContext.delete(entry)
}else {
set.insert(entry.isbn!)
}
}
try fetchRequestController.performFetch()
print(fetchRequestController.fetchedObjects?.count)
} catch {
fatalError()
}
答案 10 :(得分:0)
Swift 3.1最优雅的解决方案(Thanx dfri)
Apple Swift 3.1版(swiftlang-802.0.51 clang-802.0.41)
func uniq<S: Sequence, E: Hashable>(source: S) -> [E] where E==S.Iterator.Element {
var seen: [E:Bool] = [:]
return source.filter({ (v) -> Bool in
return seen.updateValue(true, forKey: v) == nil
})
}
struct Post : Hashable {
var id : Int
var hashValue : Int { return self.id }
}
func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
var Posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)]
print(Posts)
/* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */
var myUniquePosts = uniq(source: Posts)
print(myUniquePosts)
/*[Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)]*/
答案 11 :(得分:0)
struct Post {
var id: Int
}
extension Post: Hashable {
var hashValue: Int {
return id
}
static func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
}
和其他扩展程序
public extension Sequence {
func distinct<E: Hashable>() -> [E] where E == Iterator.Element {
return Array(Set(self))
}
}
答案 12 :(得分:0)
这是一个数组扩展,用于基于给定的键返回对象的唯一列表:
extension Array {
func unique<T:Hashable>(map: ((Element) -> (T))) -> [Element] {
var set = Set<T>() //the unique list kept in a Set for fast retrieval
var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
for value in self {
if !set.contains(map(value)) {
set.insert(map(value))
arrayOrdered.append(value)
}
}
return arrayOrdered
}
}
以您的示例为例:
let uniquePosts = posts.unique{$0.id ?? ""}
答案 13 :(得分:0)
这是一个比这里更流行的变体更不专门的问题:https://stackoverflow.com/a/33553374/652038
使用我的答案,您可以这样做:
posts.firstUniqueElements(\.id)
答案 14 :(得分:0)
保留原始顺序的通用解决方案是:
extension Array {
func unique(selector:(Element,Element)->Bool) -> Array<Element> {
return reduce(Array<Element>()){
if let last = $0.last {
return selector(last,$1) ? $0 : $0 + [$1]
} else {
return [$1]
}
}
}
}
let uniquePosts = posts.unique{$0.id == $1.id }
答案 15 :(得分:-1)
我的解决方法是:
for i in 0...modelList.count - 1 {
var temp = modelList.count
for j in stride(from: i + 1, to: temp - 1, by: 1) {
if modelList[i].id == modelList[j].id {
modelList.remove(at: i)
temp -= 1
}
}
}