如何使用一个公共变量对两个结构进行排序

时间:2019-05-11 17:24:30

标签: swift sorting struct

我在Swift中有两个这样的结构:

struct Friend {
    id: Int
    name: String
    biography: String
    profilePicURL: String
}

struct ProfileViews {
    id: Int
    views: Int
}

我正在尝试根据个人资料([Friend])的浏览量对好友([ProfileViews])数组进行排序。我该如何根据id来做到这一点,这在两个结构中都是相同的?问题是,有时两个结构都不匹配。例如,某个朋友可能还没有ProfileViews。例如:

Friend(id: 1, name: "PennyWise", biography: "Lorem ipsum", "test.jpg")
Friend(id: 2, name: "Bob", biography: "Dolar sit amet", "test2.jpg")
Friend(id: 3, name: "Dylan", biography: "Yes we can!", "test3.jpg")

ProfileViews(id: 1, views: 23)
ProfileViews(id: 3, views: 12)

然后我想基于视图对[Friend]数组进行排序,因此ID 1,ID 3,ID2。我该怎么做?我知道sorted(by:)函数,但似乎只能在[Friend]数组中执行此操作。但我想使用其他结构中的变量。

4 个答案:

答案 0 :(得分:2)

最简单的解决方案是将ProfileViews的值作为Friend的属性,或者甚至将概要文件视图作为Int上的Friend的属性。< / p>

如果这不可能,那么最简单的解决方案是创建个人资料视图的字典并即时查找它们。

// Create a dictionary that maps from user ids to ProfileViews:
let viewIndex = Dictionary(
    profileViews.map { views in 
        // views.id will be the key, views will be the value
        (views.id, views)
    }
    // If two views values exist with the same user ID, they will be added together
    uniquingKeysWith: { views1, views2 -> ProfileViews in
        ProfileViews(id: views1.id, views: views1.views + views2.views)
    }
)
// Sort friends by looking up the views in the viewIndex
let sortedFriends = friends.sorted(by: { friend1, friend2 -> Bool in
    (viewIndex[friend1.id]?.views ?? 0) < (viewIndex[friend2.id]?.views ?? 0)
})

答案 1 :(得分:2)

您可能希望将这些信息永久地合并在一起(通过使views成为Friend的一部分),但是如果您希望将它们分开,则仍然可以根据需要完全将它们合并在一起。做一个数据库JOIN:

struct FriendViews {
    let friend: Friend
    let views: Int
}

let friends: [Friend] = ...
let views: [ProfileViews] = ...


let friendViews = friends.map { (friend) -> FriendViews in
    let viewCount = views.first(where: { $0.id == 1 })?.views ?? 0
    return FriendViews(friend: friend, views: viewCount)
}

这样,您只需要使用您似乎了解的标准排序工具即可对friendViews进行排序。

答案 2 :(得分:2)

此解决方案将Friend和ProfileView映射到元组,然后再对其进行排序,然后再将其映射回去。

假设两个数组friendsprofiles

let sorted = friends.map { friend -> (Friend, Int) in return (friend, profiles.first(where! { $0.id == friend.id })?.views ?? -1) }
   .sorted { t1, t2 in t1.1 > t2.1 }
   .map { $0.0 }

答案 3 :(得分:1)

这是带有一些复杂性分析的另一个解决方案。假设n = profileViews.countm = friends.count

// Count the total views each id has. We use a dictionary
// because dictionary lookup is O(n) compared to an array
// search, which is O(n).
// Complexity: 2 * O(n)
let totalViews = Dictionary(grouping: profileViews, by: { $0.id })
    .mapValues { pv in pv.reduce(0, {$0 + $1.views}) }

// Complexity: O(m log m)
let sortedFriends = friends.sorted { f0, f1 in
    let view0 = totalViews[f0.id] ?? 0 // O(1)
    let view1 = totalViews[f1.id] ?? 0 // O(1)
    return view0 > view1
}

总体复杂度:2 * O(n) + O(m log m)