Как отсортировать две структуры с одной общей переменной - PullRequest
1 голос
/ 11 мая 2019

У меня есть две структуры в Swift, как это:

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

struct ProfileViews {
    id: Int
    views: Int
}

Я пытаюсь отсортировать массив Друзей ([Friend]) по количеству просмотров для профиля ([ProfileViews]).Как я могу сделать это на основе идентификатора, который одинаков в обеих структурах?Загвоздка в том, что иногда обе структуры не совпадают.Например, может быть, что у определенного друга еще нет ProfileView.Например:

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, id 2. Как я могу это сделать?Мне известна функция sorted(by:), но я могу сделать это только в массиве [Friend].Однако я хочу использовать переменные из другой структуры.

Ответы [ 4 ]

2 голосов
/ 11 мая 2019

Скорее всего, вы хотите навсегда объединить эту информацию (сделав views частью Friend), но если вы хотите оставить их отдельно, вы можете присоединиться к ним по мере необходимости точно так же, как и в базе данных. :

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 голосов
/ 11 мая 2019

Это решение отображает Friend и ProfileView в кортежи перед сортировкой, а затем отображает их обратно.

Предполагая два массива, friends и profiles:

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 }
2 голосов
/ 11 мая 2019

Самым простым решением было бы иметь значение ProfileViews в качестве свойства Friend или даже просто иметь представления профиля в виде свойства Int для Friend.

Если этоневозможно, тогда самым простым решением было бы создать словарь представлений профиля и искать их на лету.

// 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 голос
/ 12 мая 2019

Вот еще одно решение с некоторым анализом сложности.Предполагая, n = profileViews.count и m = 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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...