I'm trying to write a function that modifies an array list by removing even numbers and duplicating odd numbers. My code works just fine in removing the even numbers. However, it only duplicates some odd numbers.
For eg. my list contains: 12 11 13 14 15 13 10 The list L after L.duplicateORremove() should contain: 11 11 13 13 15 15 13 13
But this is what I get: 11 13 13 15 13 13
I'd like some help in figuring out why I'm getting this result.
This is my code so far:
template <class Type>
void arrayListType <Type>::duplicateORremove()
{
for(int i=0; i<length; i )
{
if(list[i]%2==0)
{
for (int j = i; j < length - 1; j )
list[j] = list[j 1];
length--;
}
else
{
for (int j = length; j > i; j--)
list[j] = list[j - 1];
list[i 1] = list[i];
i ;
length ;
}
}
}
This is how my class definition and main look like:
template < class Type >
class arrayListType {
public:
arrayListType(int size = 100);
~arrayListType();
void insertEnd(const Type & insertItem);
void print() const;
void duplicateORremove();
protected:
Type * list; //array to hold the list elements
int length; //stores length of list
int maxSize; //stores maximum size of the list
};
template < class Type >
arrayListType < Type > ::arrayListType(int size) {
if (size < 0) {
cerr << "The array size must be positive. Creating " <<
"an array of size 100. " << endl;
maxSize = 100;
} else
maxSize = size;
length = 0;
list = new Type[maxSize];
assert(list != NULL);
}
template < class Type >
arrayListType < Type > ::~arrayListType() {
delete[] list;
}
template < class Type >
void arrayListType < Type > ::insertEnd(const Type & insertItem) {
if (length >= maxSize)
cerr<<"Cannot insert in a full list" << endl;
else {
list[length] = insertItem;
length ;
}
}
template < class Type >
void arrayListType < Type > ::print() const {
for (int i = 0; i < length; i )
cout << list[i] << " ";
cout << endl;
}
int main()
{
arrayListType <int> L;
L.insertEnd(12);
L.insertEnd(11);
L.insertEnd(13);
L.insertEnd(14);
L.insertEnd(15);
L.insertEnd(13);
L.insertEnd(10);
cout << "List L before L.duplicateORremove() contains:" << endl;
L.print();
L.duplicateORremove();
cout << "List L after L.duplicateORremove() contains:" << endl;
L.print();
CodePudding user response:
#include <iostream>
using namespace std;
void duplicateORremove(int list[], int length) {
for(int i=0; i<length; i )
{
if(list[i]%2==0)
{
for (int j = i; j < length - 1; j )
list[j] = list[j 1];
length--;
i-=1;
}
else
{
for (int j = length; j > i; j--)
list[j] = list[j - 1];
list[i 1] = list[i];
i ;
length ;
}
}
for (int i=0; i<length; i ) {
cout << list[i];
cout << " ";
}
}
int main()
{
int arrlist[] = {12, 11, 13, 14, 15, 13, 10};
duplicateORremove(arrlist, 7);
return 0;
}
You are not resetting the 'i' value to traverse from the previous state when an even number is found. Because of that odd number taking place of an even number is skipped while looping, and, hence you will end up with a result that has some values missing in the result. And the count of missing values will be equal to the count of even number in your input.
Just add that reset condition and it will work.
Link to run the above code: Online cpp compiler
CodePudding user response:
Here's a solution using Range-v3 library.
- You can operate on a view of the original range.
- Remove the even elements.
- Duplicate each element of the remaining list (the odd ones).
- Then convert the view back into a vector and return it.
#include <fmt/ranges.h>
#include <range/v3/all.hpp>
template <typename Range>
auto duplicate_or_remove(Range&& r) {
using namespace ranges::v3;
auto even = [](int i) { return 0 == i % 2; };
return r
| views::remove_if(even)
| views::for_each([](auto e){ return yield_from(views::repeat_n(e, 2)); })
| to_vector;
}
int main() {
std::vector<int> v{12, 11, 13, 14, 15, 13, 10};
fmt::print("{}", duplicate_or_remove(v));
}
// Outputs:
//
// [11, 11, 13, 13, 15, 15, 13, 13]
Going back to your code, notice that you cannot simply work over your input list. What would happen if the list only contained odd numbers? For the first element, you would be writing beyond the memory reserved for the list. Instead, if you need to stick to using arrays, what you can do is:
- Count the odd elements in your input list.
- Create a new array sized twice the number of odd elements in the input list.
- Walk over the input list and, for each odd element, add it twice to the newly created array.
- Return a pair consisting of the new array and its size.
- The code below also uses a nice trick to avoid passing the length of an array to a funcion if what you are passing is an array and not a pointer.
#include <iostream> // cout
#include <utility> // pair
auto is_odd = [](int i){ return (i % 2) == 1; };
template <size_t length>
size_t count_odd_elements(int (&list)[length]) {
size_t ret{};
for (size_t i{0}; i < length; i) {
if (is_odd(list[i])) {
ret ;
}
}
return ret;
}
template <size_t length>
auto duplicate_or_remove(int (&list)[length]) {
size_t odd_elements{ count_odd_elements(list) };
size_t ret_size{odd_elements * 2};
int* ret = new int[ret_size];
size_t head{};
for (size_t i{0}; i < length; i) {
int n{ list[i] };
if (is_odd(n)) {
ret[head ] = n;
ret[head ] = n;
}
}
return std::pair<int*, size_t>{ret, ret_size};
}
void print_list(int list[], size_t length) {
std::cout << "[";
for (size_t i{0}; i < length; i) {
std::cout << ((i == 0) ? "" : ", ") << list[i];
}
std::cout << "]";
}
int main() {
int arrlist[] = {12, 11, 13, 14, 15, 13, 10};
auto [result, result_size] = duplicate_or_remove(arrlist);
print_list(result, result_size);
delete[] result;
}
// Outputs:
//
// [11, 11, 13, 13, 15, 15, 13, 13]
Again, using std::vector
instead of arrays simplify things a lot:
#include <fmt/ranges.h>
#include <iostream> // cout
#include <vector>
auto is_odd = [](int i){ return (i % 2) == 1; };
auto duplicate_or_remove(const std::vector<int>& list) {
std::vector<int> ret{};
for (auto i : list) {
if (is_odd(i)) {
ret.push_back(i);
ret.push_back(i);
}
}
return ret;
}
int main() {
std::vector<int> v{12, 11, 13, 14, 15, 13, 10};
auto result{ duplicate_or_remove(v) };
fmt::print("{}", result);
}