Форум программистов, компьютерный форум, киберфорум
Unity, Unity3D
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404

Проблема с одинаковыми элементами списка

15.11.2018, 22:16. Показов 3203. Ответов 13
Метки list (Все метки)

Студворк — интернет-сервис помощи студентам
В данный момент я использую словарь(Dictionary<int, int>, key - id предмета, value - кол-во предмета), но как известно он не может хранить два одинаковых ключа, как поступить, если в качестве ключа используется id предмета в базе данных(ScriptableObject).

При добавлении предмета в словарь происходит проверка на наличие ключа, если нет, я его добавляю, если есть, я прибавляю значение(value) предмета, но что делать когда количество предмета достигнет максимума? (int maxStack в Item)

Есть идея вместо словаря использовать два списка, List<int> items и List<int> counts, но проблема в доступе к предметам, так как id предмета не будет соответсвовать индексу листа.

Подскажите прямую и гладкую дорогу.

Item.cs:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System.Collections.Generic;
using UnityEngine;
 
[System.Serializable]
public class Item
{
    public int id;
    public string name;
    public string description;
    public int maxStack;
    public Sprite icon;
    public GameObject prefab;
    public List<Attribute> attributes = new List<Attribute>();
    
    public Item() { }
 
    public Item(int id, string name, string description, Sprite icon, GameObject prefab, List<Attribute> attributes)
    {
        this.id = id;
        this.name = name;
        this.description = description;
        this.icon = icon;
        this.prefab = prefab;
        this.attributes = attributes;
    }
 
    /// <summary>
    /// Копия.
    /// </summary>
    /// <returns>Возвращает копию данного предмета</returns>
    public Item GetCopy() => (Item)MemberwiseClone();
}
Inventory.cs:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
using UnityEngine;
using System.Collections.Generic;
 
public class Inventory : MonoBehaviour
{
    /*#region Singleton
 
    private static Inventory instance;
    public static Inventory Instance { get; private set; }
 
    private void Awake()
    {
        instance = this;
    }
 
    #endregion*/
 
    public ItemDatabase itemDatabase;
 
    [SerializeField] private bool hideOnStart = true;
    [SerializeField] private KeyCode inventoryKeyCode = KeyCode.Tab;
    [SerializeField] private GameObject inventory;
    [SerializeField] private RectTransform container;
    public Drag dragPrefab;
 
    private Dictionary<int, int> items = new Dictionary<int, int>();
    private List<Slot> slots = new List<Slot>();
 
    /// <summary>
    /// Добавляет предмет в инвентарь.
    /// </summary>
    /// <param name="id">Идентификатор предмета</param>
    /// <param name="count">Количество предмета</param>
    /// <returns></returns>
    public bool Add(int id, int count)
    {
        //var item = itemDatabase.GetItemById(id).GetCopy();
 
        var sameSlot = GetSameSlot(id);
        if (sameSlot && itemDatabase.GetItemById(id).maxStack <= count) // --- TODO: сделать проверку на максимальное количество предмета
        {
            if (items.ContainsKey(id))
            {
                items[id] += count;
                sameSlot.onItemChanged(id, items[id]);
                return true;
            }
            else return false;
        }
 
        var emptySlot = GetEmptySlot();
        if (emptySlot)
        {
            if (!items.ContainsKey(id)) // ----------------------------------- TODO: придумать что-то с добавление предметов с одинаковыми Id
            {
                items.Add(id, count);
                emptySlot.onItemAdded(id, count);
                return true;
            }
            else return false;
        }
        else return false;
    }
 
    /// <summary>
    /// Удаляет предмет из инветаря.
    /// </summary>
    /// <param name="id">Идентификатор предмета</param>
    /// <returns>Возвращает true в случае успешного удаления предмета из инвентаря</returns>
    public bool Remove(int id)
    {
        var slot = GetSlot(id);
        if (slot)
        {
            if (items.ContainsKey(id))
            {
                items.Remove(id);
                slot.onItemRemoved();
                return true;
            }
            else return false;
        }
        else return false;
    }
 
    /// <summary>
    /// Удаляет предмет из инвентаря по заданному количуству.
    /// </summary>
    /// <param name="id">Идентификатор предмета</param>
    /// <param name="count">Количество для удаления</param>
    /// <returns>Возращает true в случае успешного уменьшения количества или полного удаления предмета из инвентаря</returns>
    public bool RemoveBy(int id, int count)
    {
        var slot = GetSlot(id);
        if (slot)
        {
            if (items.ContainsKey(id))
            {
                if (items[id] == 1)
                {
                    items.Remove(id);
                    slot.onItemRemoved();
                    return true;
                }
                else
                {
                    items[id] -= count;
                    slot.onItemChanged(id, items[id]);
                    return true;
                }
            }
            else return false;
        }
        else return false;
    }
 
    public int GetCount(int id) => items[id];
 
    public bool SetCount(int id, int count)
    {
        if (!items.ContainsKey(id))
            return false;
 
        items[id] = count;
        return true;
    }
 
    public int AddCount(int id, int count, int amount)
    {
        if (!items.ContainsKey(id))
            return 0;
 
        var residue = count - amount;
        items[id] += residue;
        return residue;
    }
 
    private void Start()
    {
        slots = GetSlots();
 
        if (hideOnStart)
            inventory.SetActive(false);
    }
 
    private void Update()
    {
        if (Input.GetKeyDown(inventoryKeyCode))
        {
            inventory.SetActive(!inventory.activeSelf);
            PlayerMouseLook.LockCursor(!inventory.activeSelf, true);
        }
 
        if (Input.GetKeyDown(KeyCode.T))
            RemoveBy(5, 1);
        if (Input.GetKeyDown(KeyCode.Y))
            Remove(5);
    }
 
    /// <summary>
    /// Все слоты.
    /// </summary>
    /// <returns>Возвращает лист со всеми слотами в инвентаре</returns>
    private List<Slot> GetSlots()
    {
        List<Slot> temp = new List<Slot>();
        for (int i = 0; i < container.childCount; i++)
        {
            var child = container.GetChild(i);
            var childContainer = child.Find("Container");
            for (int j = 0; j < childContainer.childCount; j++)
            {
                var newChild = childContainer.GetChild(j);
                var slot = newChild.GetComponent<Slot>();
                slot.inventory = this;
                temp.Add(slot);
            }
        }
        return temp;
    }
 
    /// <summary>
    /// Пустой слот.
    /// </summary>
    /// <returns>Возвращает пустой слот в инвентаре</returns>
    private Slot GetEmptySlot()
    {
        for (int i = 0; i < slots.Count; i++)
        {
            var slot = slots[i];
            if (slot.IsEmpty)
                return slot;
        }
        return null;
    }
 
    /// <summary>
    /// Похожий слот по идентификатору предмета.
    /// </summary>
    /// <param name="id">Идентификатор предмета</param>
    /// <returns>Возвращает слот имеющий такой же идентификатор предмета</returns>
    private Slot GetSameSlot(int id)
    {
        for (int i = 0; i < slots.Count; i++)
        {
            var slot = slots[i];
            if (!slot.IsEmpty && slot.drag.Id == id)
                return slot;
        }
        return null;
    }
 
    /// <summary>
    /// Слот по идентификатору предмета.
    /// </summary>
    /// <param name="id">Идентификатор предмета</param>
    /// <returns>Возвращает слот с данным идентификатором предмета</returns>
    private Slot GetSlot(int id)
    {
        for (int i = 0; i < slots.Count; i++)
        {
            var slot = slots[i];
            if (!slot.IsEmpty && slot.drag.Id == id)
                return slot;
        }
        return null;
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
15.11.2018, 22:16
Ответы с готовыми решениями:

В целочисленной матрице nxn найти номера строк с одинаковыми элементами, и с элементами, расположенными по возрастанию
Задана целочисленная квадратная матрица n-го порядка. Найти номера строк, которые имеют: а) все одинаковые элементы; б) элементы,...

Разделение строки с одинаковыми элементами
Как отделить от строки MAUI_06B_W07_12 последнее значение?

Матрицы. Строка с одинаковыми элементами.
Дан двумерный массив размером n*m, заполненный случайными числами. Определить, есть ли в данном массиве строка в которой имеются одинаковые...

13
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
16.11.2018, 09:43
Почему бы в класс Slot не добавить ссылку на item, которую он содержит (или не содержит) и количество itemCount этих предметов.
Инвентарь будет содержать список этих слотов.
0
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
16.11.2018, 10:45  [ТС]
jetyb, слот содержит ссылку на drag, в котором содержаться ссылка на item и count.

Добавлено через 53 секунды
Drag создаётся когда предмет добавляется и т.д.
0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
16.11.2018, 11:35
Лучший ответ Сообщение было отмечено NotGoodEnough как решение

Решение

Не понимаю.
Инвентарь содержит список слотов, каждый слот знает какую item и сколько он содержит. Может быть несколько слотов с одними и теми же item-ами(типа стаки зелей). Этого достаточно для реализации функций

public bool Add(int id, int count)
public bool Remove(int id, int count)
public bool GetItemCount(int id)

В случае Add пробегаемся по всем слотам, пустым или с item-ами такого типа, суммируем число свободных мест в них.
Если места хватает, то добавляем в свободные или подобные слоты предметы. В случае Remove проверяем через GetItemCount число item-ов в инвентаре, а затем пробегаемся по всем слотам и удаляем из них item.
В обоих функциях по-любому надо пробежаться по всем слотам, и Dictionary<int, int> items не нужен.

Функцию же GetItemCount можно реализовать и без Dictionary<int, int> items. Да, выполняться она будет помедленнее. Но ведь добавление\удаление предметов в инвентарь - разовая операция, которая не вызывается часто.
Там вам по-любому придется и интерфейс инвентаря обновлять.

Можно конечно же и завести свой private Dictionary<int, int> itemCounts для быстрой работы функции GetItemCount. Модифицировать этот словарь только в методах Add/Remove/Load.
Цитата Сообщение от NotGoodEnough Посмотреть сообщение
но что делать когда количество предмета достигнет максимума? (int maxStack в Item)
Никакого предела для значений словаря тут существовать не может. Например может быть 3 стека с maxStack лечебными зельями, тогда значение словаря 3*maxStack . Максимум предметов тут контролируется слотами.
1
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
16.11.2018, 14:07  [ТС]
Цитата Сообщение от jetyb Посмотреть сообщение
Никакого предела для значений словаря тут существовать не может
Про пределы значений словоря ничего не говорилось!
Я писал только про то, что словарь не может содержать одинаковых ключей.

Добавлено через 1 минуту
Цитата Сообщение от jetyb Посмотреть сообщение
Например может быть 3 стека с maxStack лечебными зельями, тогда значение словаря 3*maxStack . Максимум предметов тут контролируется слотами.
Вы предлагаете, использовать один элемент из словоря для нескольких слотов с одинаковыми предметами?
0
 Аватар для 1max1
3362 / 1775 / 1028
Регистрация: 26.10.2018
Сообщений: 5,204
16.11.2018, 14:13
Что-то я не понял в чем проблема? Нужно запретить добавление если предметов больше чем maxCount?
Не проще ли хранить словарь типа <int, Item>, где ключ ид, значение - сам предмет. В класс итем добавить поле с количеством предметов на данный момент.
0
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
16.11.2018, 15:03  [ТС]
1max1, суть в том, что при достижении какого-либо предмета собственного maxCount нужно чтобы создался другой такой же предмет, в другом слоте.
Цитата Сообщение от 1max1 Посмотреть сообщение
Не проще ли хранить словарь типа <int, Item>, где ключ ид, значение - сам предмет
Пока что это единственное решение, Dictionary<Item, int>, то есть ключ - предмет, значение - количество.

Добавлено через 3 минуты
Ещё jetyb, как я понял, предлагал использовать один элемент в словаре для нескольких слотов, но я не знаю на сколько это будет удобно. Изначально я предпологал использование одного элемента словаря для одного слота, но сейчас у меня есть сомнения в удобстве.
0
 Аватар для 1max1
3362 / 1775 / 1028
Регистрация: 26.10.2018
Сообщений: 5,204
16.11.2018, 15:04
Цитата Сообщение от NotGoodEnough Посмотреть сообщение
1max1, суть в том, что при достижении какого-либо предмета собственного maxCount нужно чтобы создался другой такой же предмет, в другом слоте.
List<Dictionary<int, Item>>, но наверное это уже слишком накручено будет...
0
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
16.11.2018, 15:31  [ТС]
Цитата Сообщение от 1max1 Посмотреть сообщение
List<Dictionary<int, Item>>
слишком =)
0
 Аватар для 1max1
3362 / 1775 / 1028
Регистрация: 26.10.2018
Сообщений: 5,204
16.11.2018, 15:42
А если добавить в класс итем поле, с номером слота, где он лежит?
0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
16.11.2018, 15:58
Я писал, что для организации инвентаря и всех его функций достаточно:
1. хранить в инвентаре список слотов
2. в каждом слоте хранить ссылку на item и число этих item-ов в слоте
1
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
16.11.2018, 16:24  [ТС]
jetyb, я же говорю, что у меня есть item и count в скрипте drag, который нужен для перемещения предметов по инвентарю, не создавать же мне новый драг каждый раз когда я захочу переместить предмет в другой слот.

Добавлено через 2 минуты
1max1,
Цитата Сообщение от 1max1 Посмотреть сообщение
А если добавить в класс итем поле, с номером слота, где он лежит?
не вариант, у меня инвентарь динамический, нужно будет мучаться с циклами для поиска слотов, плюс к этому ещё и хотбар.
0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
16.11.2018, 19:45
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
        public class Item
        {
            public int id;
            public string name;
            public int maxCountInSlot = 1;
        }
 
        public class Slot
        {
            public int index;
            public Item item;
            public int itemCount;
        }
 
        public class Inventory
        {
            public int capacity = 100;
            public List<Slot> slots = new List<Slot>();
 
            public bool HasFreeSpace(Item item, int count = 1)
            {
                if (item == null) return false;
                var freeSpace = (capacity - slots.Count)*item.maxCountInSlot;
                for (var i = 0; i < slots.Count && count < freeSpace; i++)
                {
                    var slot = slots[i];
                    if (slot.item != null && slot.item.id == item.id) freeSpace += item.maxCountInSlot - slot.itemCount;
                }
                return count <= freeSpace;
            }
 
            public int GetItemCount(Item item)
            {
                return item == null ? 0 : slots.Where(s => s.item.id == item.id).Sum(s => s.itemCount);
            }
 
            public bool Add(Item item, int count = 1)
            {
                if(!HasFreeSpace(item, count)) return false;
                foreach (var slot in slots)
                {
                    if (slot.item.id != item.id || slot.itemCount == item.maxCountInSlot) continue;
                    var freeSpace = item.maxCountInSlot - slot.itemCount;
                    if (count <= freeSpace)
                    {
                        slot.itemCount += count;
                        break;
                    }
 
                    slot.itemCount = item.maxCountInSlot;
                    count -= freeSpace;
                }
                while (count > 0 && slots.Count < capacity)
                {
                    var slot = GetFreeSlot();
                    slot.item = item;
                    if (count <= item.maxCountInSlot)
                    {
                        slot.itemCount = count;
                        break;
                    }
                    slot.itemCount = item.maxCountInSlot;
                    count -= item.maxCountInSlot;
                }
                return true;
            }
 
            public bool Remove(Item item, int count = 1)
            {
                if (item == null) return true;
                if (GetItemCount(item) < count) return false;
                //в таком порядке удаление не нарушит индексацию, и обход правильный
                for (var i = slots.Count - 1; i >= 0 && count > 0; i--)
                {
                    var slot = slots[i];
                    if(slot.item.id != item.id) continue;
                    if (count < slot.itemCount)
                    {
                        slot.itemCount -= count;
                        break;
                    }
                    count -= slot.itemCount;
                    ClearSlot(slot);
                }
 
                return true;
            }
 
 
            /// <summary>
            /// Создание или получение свободного слота
            /// (в зависимости от того, бездонный ли или ограниченный  инвентарь)
            /// </summary>
            private Slot GetFreeSlot()
            {
                var slot = new Slot();
                slots.Add(slot);
                return slot;
            }
 
            /// <summary>
            /// Удаление или очистка слота 
            /// </summary>
            private void ClearSlot(Slot slot)
            {
                slots.Remove(slot);
            }
 
        }
Методы GetFreeSlot и ClearSlot детальнее делайте сами.
1
 Аватар для NotGoodEnough
34 / 30 / 8
Регистрация: 22.02.2017
Сообщений: 404
17.11.2018, 14:27  [ТС]
jetyb, буду смотреть
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
17.11.2018, 14:27
Помогаю со студенческими работами здесь

Матрицы с одинаковыми элементами в углах?!
У меня есть рандомная матрица, помогите пожалуйста, как в ней выявить квадратные матрицы с одинаковыми элементами в углах?? ...

Вывести номера строк с одинаковыми элементами
Мне нужно написать функцию что выводит номера строк с двумерного массива с одинаковыми положительными элементами. Я не могу придумать...

Создание матрицы со всеми одинаковыми элементами
Ребят, помогите, наткнулся на проблему, ни как не могу придумать как сделать матрицу m*n чтоб во всех элементах стояло &quot;=&quot; ...

Падение программы с двумя одинаковыми элементами не воспроизводится
#include &quot;pch.h&quot; #include &lt;iostream&gt;; #include &lt;cstdlib&gt; #include &lt;ctime&gt; #include &lt;windows.h&gt;; #include &lt;vector&gt; using...

Сравнить два массива и вывести третий с одинаковыми элементами
Приветствую. Возник вопрос, темы не найдено( Нужно сравнить два рандомно заполненных одномерных массива на 10 элементов. Если есть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а привычная функция main(). . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru