Вот моя собственная реализация синглетонов. Все, что вам нужно сделать, это украсить класс; для получения синглтона вы должны использовать метод Instance
. Вот пример:
@Singleton
class Foo:
def __init__(self):
print 'Foo created'
f = Foo() # Error, this isn't how you get the instance of a singleton
f = Foo.Instance() # Good. Being explicit is in line with the Python Zen
g = Foo.Instance() # Returns already created instance
print f is g # True
И вот код:
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Other than that, there are
no restrictions that apply to the decorated class.
To get the singleton instance, use the `Instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
Limitations: The decorated class cannot be inherited from.
"""
def __init__(self, decorated):
self._decorated = decorated
def Instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
Я собираюсь предложить два решения.
Оба подхода потребуют Post
, чтобы быть Hashable
и Equatable
Здесь я предполагаю, что ваш Post
struct (или класс) имеет свойство 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
}
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)]*/
(Обновлено для Swift 3)
Как я уже упоминал в своем комментарии к вопросу, вы можете использовать модифицированное решение Daniel Kroms в ранее отмечалось, что это сообщение дублируется . Просто сделайте свой объект Post
hashable (неявно равнозначным с помощью свойства 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
extension
В качестве альтернативы использованию свободной функции мы могли бы реализовать 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)] */
Вместо использования объекта hashable вы можете просто использовать набор. Возьмите значение атрибута, для которого вы хотите удалить дубликаты, и используйте это как тестовое значение. В моем примере я проверяю наличие повторяющихся значений 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()
}
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))
}
}
Это также работает для многомерных массивов:
for (index, element) in arr.enumerated().reversed() {
if arr.filter({ $0 == element}).count > 1 {
arr.remove(at: index)
}
}
Сохранение порядка, без добавления дополнительного состояния:
func removeDuplicates<T: Equatable>(accumulator: [T], element: T) -> [T] {
return accumulator.contains(element) ?
accumulator :
accumulator + [element]
}
posts.reduce([], removeDuplicates)
В swift 3 см. ниже код:
let filterSet = NSSet(array: orignalArray as NSArray as! [NSObject])
let filterArray = filterSet.allObjects as NSArray //NSArray
print("Filter Array:\(filterArray)")
мои «чистые» решения Swift без соответствия Post для Hashable (требуется 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) инкапсулировать в функцию (aka func unique(posts:[Post])->[Post]
), возможно, расширение Array .. ..
используйте 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}())!)]
Создайте набор из массива с помощью duplates
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)
}
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]
Solution 2
.alreadyThere.contains
в моем коде является обязательным, потому что мне нужно знать, присутствует лиpost
, который я оцениваю, в массиве, который я создаю и возвращаю. Вы не можете удалить эту часть. если вам нужны уникальные значения. – Luca Angeletti 12 January 2016 в 14:57