How to iterate through a vector of tuple and remove duplicate indexes

Mar 9, 2021 at 7:44am
I have a vector of tuple and I push back an item in it, then if i push back the same item, i want it search the vector of tuple and if it finds the same item, then dont add it to the inventory or remove duplicate, but I cant seem to figure out how. I tried to use an iterator but it keeps giving me an error.

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
vector<tuple<string, int>> inventory;


    inventory.push_back(make_tuple("Katana", 1));
    inventory.push_back(make_tuple("Steel Arrows", 66));

    cout << "\nOutput Potion and amount owned" << endl;

    cout << "Item Name: " << get<0>(inventory[0]) << endl;
    cout << "Item Amount: " << get<1>(inventory[0]) << endl;

    cout << "\nOutput Katana and amount owned" << endl;

    cout << "Item Name: " << get<0>(inventory[1]) << endl;
    cout << "Item Amount: " << get<1>(inventory[1]) << endl;

    cout << "\nOutput Steel Arrows and amount owned" << endl;

    cout << "Item Name: " << get<0>(inventory[2]) << endl;
    cout << "Item Amount: " << get<1>(inventory[2]) << endl;


    cout << "\n\nManual Search\n" << endl;

    cout << "Inventory Size: " << inventory.size() << endl;

    vector<tuple<string, int>>::iterator itr = std::find(inventory.begin(), inventory.end(), "Katana");

    if (itr != inventory.end())
    {
        cout << "Found katana" << endl;
    }
    else
    {
        cout << "did not find katana" << endl;
    }

    cout << "Inventory Size: " << inventory.size() << endl;
Last edited on Mar 9, 2021 at 7:44am
Mar 9, 2021 at 8:18am
The problem is on line 27. You provide a string argument but find expects a tuple.
You better use find_if with a lambda, sth. like this:
1
2
3
4
5
6
7
8
9
auto it = find_if(inventory.begin(), inventory.end(), [](const auto& t)
  {
    return get<0>(t) == "Katana";
  });

  if(it != inventory.end())
    cout << "Found Katana";
  else
    cout << "Couldn't find Katana";


BTW. Why don't you use a struct or class instead of a tuple. Tuples are more useful for generic code, but you have a concrete type, probably a weapon.
Mar 9, 2021 at 8:51am
Well in my other project I have a tuple as the players inventory in the player class, the tuple holds an Item object and an int which represents how much for that item the player has, i could have used pair but i decided on tuple and I can easily expand it when needed, like say if I need it to hold an ID for the item as well. This code above I wrote in a blank project to just try to understand how tuple works and how to iterate through it.
Last edited on Mar 9, 2021 at 8:51am
Mar 9, 2021 at 12:58pm
What would be a better way to do an inventory? is just a vector that holds Item objects fine? I've been thinking about this for a few hours. and in my program I have an item class and the constructor looks like this:

1
2
3
Item WeakPotion  ("Weak Potion",   init.cost = 20, init.effect = 10);
Item StrongPotion("Strong Potion", init.cost = 40, init.effect = 25);
Item SuperPotion ("Super Potion",  init.cost = 65, init.effect = 45);


Players inventory is this:

vector<tuple<Item, int>> mInventory{ 0 };

I could just do

inv[0].GetName();

with a regular vector and add a variable to Item that tracks how many the player has in their inventory, but I dont really know. I almost feel like that variable belongs in the player class, but im unsure.

I have it as a tuple so i can track the item and the amount owned and increment/decrement the amount owned easily, but I guess I could do that another way as well, just not too sure how yet.
Last edited on Mar 9, 2021 at 1:00pm
Mar 9, 2021 at 1:42pm
Use a vector of struct. Consider:

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
#include <vector>
#include <string>

struct Invent {
	std::string name;
	int amnt {};
};

int main()
{
	const std::vector<Invent> inventory {{"Katana", 1}, {"Steel Arrows", 66}};

	std::cout << "\nOutput Katana and amount owned\n";
	std::cout << "Item Name: " << inventory[0].name << '\n';
	std::cout << "Item Amount: " << inventory[0].amnt << '\n';

	std::cout << "\nOutput Steel Arrows and amount owned\n";
	std::cout << "Item Name: " << inventory[1].name << '\n';
	std::cout << "Item Amount: " << inventory[1].amnt << '\n';

	std::cout << "\n\nManual Search\n";

	std::cout << "Inventory Size: " << inventory.size() << '\n';

	const auto itr {std::find_if(inventory.begin(), inventory.end(), [](const auto& inv) {return inv.name == "Katana"; })};

	if (itr != inventory.end())
		std::cout << "Found katana\n";
	else
		std::cout << "did not find katana\n";
}

Mar 9, 2021 at 4:07pm
Would I just be able to use composition?

This is a very basic example I just whipped this up to illustrate what I'm talking about, it's my first attempt at using composition as well, I think I may have wound up just using individual classes as their own thing though.

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
#include <iostream>
#include <string>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

class Item
{
    public:
        Item(const string& name, int amountOwned): mName(name), mAmountOwned(amountOwned)
        {}
        Item() = default;

	string GetName() const { return mName; }
	int GetAmountOwned() const { return mAmountOwned; }
	void GiveOne();
        void GiveMultiple(int amount);

    private:
        string mName{ "Item Name" };
	int mAmountOwned{ 0 };
};

void Item::GiveMultiple(int amount)
{
    mAmountOwned += amount;
}

void Item::GiveOne()
{
    mAmountOwned++;
}

class Inventory
{
    public:
	Inventory() = default;

        void Add(Item& item);
	void Open();

    private:
        vector<Item> mInventory{ 0 };
};

void Inventory::Add(Item& item)
{
    item.GiveOne();
    mInventory.push_back(item);
}

void Inventory::Open()
{
    for (auto& i : mInventory)
    {
        cout << i.GetName() << "(";
        cout << i.GetAmountOwned() << ")" << endl;
    }
}


class Player
{
    public:
        Player(const string& name, Inventory& inventory): mName(name), mInventory(inventory)
        {}

    private:
        string mName{ "Player Name" };
        Inventory mInventory;
};

int main()
{
    Item Potion("Potion", 0);
    Item Sword("Sword", 0);

    Inventory PlayerInventory;

    Potion.GiveOne();
    Potion.GiveOne();

    Sword.GiveMultiple(6);

    PlayerInventory.Add(Potion);
    PlayerInventory.Add(Sword);

    Player Link("Link", PlayerInventory);

    PlayerInventory.Open();
}
Last edited on Mar 9, 2021 at 4:20pm
Topic archived. No new replies allowed.