0

I have an array that looks like this (the real one is much longer, with around 150 elements):

static const MyConfig m_Original[] =
{
    {0x01, 0x04, 0}, 
    {0x02, 0x0A, 0},
    {0x03, 0x54, 0}, 
    {0x01, 0x05, 0},
    {0xA1, 0xE5, 0}, 
    {0xA2, 0x6B, 0}, 
    {0xA3, 0x2B, 0}, 
    {0xA1, 0xE3, 0}, 
};

In certain cases I would like to use almost the same array, but with a couple changes.

So I did a "patch" array:

static const MyConfig m_Patch[] =
{
    {0x01, 0x0F, 0}, 
    {0x02, 0x0F, 0},
    {0xA1, 0xFF, 0}, 
};

Note that the it is the only second value of each element (the value) the one that changes.

So, I would like to replace those 3 (maybe more in real life) values from the original array. And! as you see, some value are repeated, all repetitions should be replaced.

The two immediate solutions are:

  1. Just create a new array with the needed values (but then I'm allocating a big array that I will never use.

  2. Write a for loop comparing each element of each array and replacing if exists, which doesn't seem elegant (maybe I'm wrong (?))

The question: is there an optimal way of achieving this?

So at the end I would like m_Original to look like:

    {0x01, 0x0F, 0}, => Replaced
    {0x02, 0x0F, 0}, => Replaced
    {0x03, 0x54, 0}, 
    {0x01, 0x0F, 0}, => Replaced
    {0xA1, 0xFF, 0}, => Replaced
    {0xA2, 0x6B, 0}, 
    {0xA3, 0x2B, 0}, 
    {0xA1, 0xFF, 0}, => Replaced

FYI:

typedef struct
{
    uint16_t Addr;
    uint16_t Value;
    uint32_t time;
} MyConfig ;

EDIT: m_Original should not be sorted, its order is important

9
  • 2
    Firstly, "elegant" is extremely subjective and solicits opinion-based answers that are off-topic here. Secondly, your problem is not clear. You've mentioned that "some values are repeated" while listing whole structures. To me, each struct is a single value, but based on your example it looks like you're only comparing the Addr when matching. Is that the case? A simple solution would be to index your "patch" array with something like std::unordered_map<uint16_t, const MyConfig*> and then use that in a loop. This avoids needing to loop over every patch element for every candidate. Commented Apr 23, 2021 at 7:36
  • An alternative to the above is to ensure you always store your patch with the addresses in sorted order. Then you can binary-search the array (using std::lower_bound for example) without needing to construct any index at runtime. Commented Apr 23, 2021 at 7:39
  • @paddy you're right I'm edditing the question to specify that i'ts about the addres. Commented Apr 23, 2021 at 7:40
  • @paddy about "elegant", true, maybe I'm looking for "optimal" (?) Commented Apr 23, 2021 at 7:41
  • 1
    Can you use std::unordered_map<uint16_t , MyConfig>? Commented Apr 23, 2021 at 7:42

1 Answer 1

2

Is there a reason you do not want to use a std::map or std::vector? However this is a possible solution with vector. It can be modified to use std::array if you like:

#include <vector>
#include <cstdint>

namespace { // Prefer anonymous namespaces before static

struct MyConfig // Use c++ syntax
{
    uint16_t Addr;
    uint16_t Value;
    uint32_t time;
};

const std::vector<MyConfig> m_Original =
{
    {0x01, 0x04, 0}, 
    {0x02, 0x0A, 0},
    {0x03, 0x54, 0}, 
    {0x01, 0x05, 0},
    {0xA1, 0xE5, 0}, 
    {0xA2, 0x6B, 0}, 
    {0xA3, 0x2B, 0}, 
    {0xA1, 0xE3, 0}, 
};

const std::vector<MyConfig> m_Patch =
{
    {0x01, 0x0F, 0}, 
    {0x02, 0x0F, 0},
    {0xA1, 0xFF, 0}, 
};

auto patch (std::vector<MyConfig> array,
            const std::vector<MyConfig> &patch) -> std::vector<MyConfig> {
    for (auto &o: array) {
        for (const auto & p: patch) {
            if (o.Addr == p.Addr) {
                // Replace values with the same address
                o = p;
            }
        }
    }

    return array;
}

} // namespace

int main() {
    auto patched = patch(m_Original, m_Patch);

    for (auto values: patched) {
        std::cout << std::hex << values.Addr << ", " << values.Value << "\n";
    }
}

Resulting output:

1, f
2, f
3, 54
1, f
a1, ff
a2, 6b
a3, 2b
a1, ff

If you want to change your original array (you dont, this is really bad practice) you do like this

    const_cast<std::vector<MyConfig>&>(m_Original) = patch(m_Original, m_Patch);

If you want to unnest the loop and obfuscate it a bit, you can define some more functions like this (also not recommended)

auto patch (std::vector<MyConfig> array,
            const std::vector<MyConfig> &patch) -> std::vector<MyConfig> {

    auto replace_if_in_patch = [&patch] (auto &value) {
        for (auto &p: patch) {
            if (value.Addr == p.Addr) {
                value = p;
                return;
            }
        }
    };

    for (auto &o: array) {
        replace_if_in_patch(o);
    }

    return array;
}

If you want a patch function that patches the incoming array, you might want to use references in the arguments

void patch (std::vector<MyConfig> array&,
    // Notice change here -------------^
            const std::vector<MyConfig> &patch) -> std::vector<MyConfig> {
    for (auto &o: array) {
    //...
    // then remove the return statement 
Sign up to request clarification or add additional context in comments.

11 Comments

If m_Original can be sorted, you may consider binary search. (std::lower_bound)
It cannot be sorted @AyxanHaqverdili , just sis an edit for clarity
Tihs looks good :) , just 2 things: 1. I wanted toavoid the nested loop and 2. the goal is to change the actual value of m_Original
@Ivan you can't change value of a const variable...
@Ivan Added examples how to do what you asking for. But please don't do it ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.