[英]Get all blocks of contiguous same numbers for an array
I have an array here我这里有一个数组
int arr[] = { 2, 6, 6, 3, -1, -1, -1, 4, -1, -1, 5, 5, -1, 7 };
// ^^^^^^^^^^ ^^^^^^
and I want to write a code that gets the number of blocks of contiguous -1
s in the array but only the ones that contain more than one -1
.我想编写一个代码来获取数组中连续的
-1
块的数量,但只包含包含多个-1
的块。
In this example there is a sequence of three contiguous -1
s and two contiguous -1
s in the array and I want to get the size of both sequences like this:在这个例子中,数组中有一个由三个连续的
-1
和两个连续的-1
组成的序列,我想得到两个序列的大小,如下所示:
3 2
3 2
You might do:你可能会这样做:
template <typename IT, typename T>
std::vector<std::size_t> count_contiguous_block(IT begin, IT end, const T& value)
{
std::vector<std::size_t> res;
auto it = begin;
do {
it = std::find(it, end, value);
auto endBlock = std::find_if(it, end, [](const auto& e){ return e != value; });
if (it != endBlock) {
res.push_back(std::distance(it, endBlock));
it = endBlock;
}
} while (it != end)
return res;
}
I want to show a solution using C++ language elements.我想展示一个使用 C++ 语言元素的解决方案。
Everything that I saw here is (except the usage of std::cout) pure C-code .我在这里看到的一切都是纯C 代码(std::cout 的用法除外)。 And that is a pity, because C++ is much more powerful and has a lot of "of-the-shell" usable algorithms.
很遗憾,因为 C++ 功能更强大,并且有很多“外壳”可用算法。
So, as a first note.所以,作为第一个注释。 You should not use C-Style arrays in C++.
您不应在 C++ 中使用 C 样式 arrays。 There can be no argument, to not use a
std::array
instead.没有理由不使用
std::array
代替。 Or, for use cases with dynamic memory management, a std::vector
.或者,对于具有动态 memory 管理的用例,一个
std::vector
。 Using a std::vector
is nearly always the better solution.使用
std::vector
几乎总是更好的解决方案。
Anyway.反正。 C++ will also still work with C-Style arrays.
C++ 仍可与 C 型 arrays 一起使用。 In my example below, I made heavy use of C++ functionality and can still work with C-Style arrays.
在下面的示例中,我大量使用了 C++ 功能,并且仍然可以使用 C-Style arrays。 Because of this programming style, I can exchange the C-Style array with modern C++ STL containers later, and, the program will still run.
由于这种编程风格,我可以稍后将 C-Style 数组与现代 C++ STL 容器交换,并且程序仍然可以运行。
But let us first see the code, which I will explain later.但是让我们先看看代码,我稍后会解释。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
// Test data
int arr[] = { 2, 3, -1, -1, -1, 4, -1, -1 };
unsigned int result[(sizeof(arr) / sizeof(arr[0]))/2];
// A predicate function that checks for 2 elements to be -1
bool twoMinusOnes(const int i, const int j) {
return i == -1 && j == -1;
}
// Test program
int main() {
// Here we count, how many contiguos blocks of -1 are available
unsigned int blockCounter = 0;
// Some iterator to the begin and end of a -1 block in a source data
decltype(std::begin(arr)) beginOfBlock{};
decltype(std::begin(arr)) endOfBlock{};
// Find all blocks with contiguos -1 in a simple for loop
for ( beginOfBlock = std::adjacent_find(std::begin(arr), std::end(arr), twoMinusOnes); // Initial value. Start searching from beginning
beginOfBlock != std::end(arr); // Check end condition
beginOfBlock = std::adjacent_find(endOfBlock, std::end(arr), twoMinusOnes)) { // find next block
// Ok. std::adjacent_found a block with at lease 2 repeating -1 for us
// Now, find the position, where this block ends
endOfBlock = std::adjacent_find(beginOfBlock, std::end(arr), std::not_equal_to<int>());
// Set iterator to past the end of the contiguous -1 block (if we are not at the end)
if (endOfBlock != std::end(arr)) std::advance(endOfBlock, 1);
// Store number of elements in this block
result[blockCounter++] = std::distance(beginOfBlock, endOfBlock);
}
// Show result to user. Number of blocks and number of elements in each block
for (unsigned int i{}; i < blockCounter; ++i)
std::cout << "Block " << i + 1 << " has " << result[i] << " elements\n";
return 0;
}
OK, what are we doing here?好的,我们在这里做什么?
First, we define an array with the source data that shall be examined.首先,我们用要检查的源数据定义一个数组。 Second, we also define a "result" array, with a fixed maximum size, equal to half the number of elements of the first array.
其次,我们还定义了一个“结果”数组,具有固定的最大大小,等于第一个数组元素数量的一半。 This, because the there cannot be more consecutive -1 blocks.
这是因为不能有更多连续的 -1 块。
Ok, then we define a so called predicate function, which simply checks if both given elements are -1.好的,然后我们定义一个所谓的谓词 function,它只是检查两个给定元素是否都是 -1。 That is what we are looking for in our source array.
这就是我们在源数组中寻找的内容。 The predicate function can then later be used in C++ standard algorithms.
谓词 function 以后可以在 C++ 标准算法中使用。
In main, we initialize a blockCounter which will show us the number of contiguous -1 blocks found.在 main 中,我们初始化一个 blockCounter,它将向我们显示找到的连续 -1 块的数量。
Then we see:然后我们看到:
decltype(std::begin(arr)) beginOfBlock{};
decltype(std::begin(arr)) endOfBlock{};
This will define an iterator, regardless of the used C++ STL container.这将定义一个迭代器,而不管使用的 C++ STL 容器。 For our
int[]
array, it will be a int*
(So, we could have also written int *beginOfBlock;
.对于我们的
int[]
数组,它将是一个int*
(因此,我们也可以编写int *beginOfBlock;
。
This is a very flexible approach and will allow us the use different containers later.这是一种非常灵活的方法,可以让我们以后使用不同的容器。
Next we start a for loop, to find all blocks of contiguous -1s.接下来我们开始一个 for 循环,以查找所有连续的 -1 块。
For this we use a dedicated function that has been designed to find adjacent elements with a certain property: std::adjacent:find
.为此,我们使用专用的 function 来查找具有特定属性的相邻元素:
std::adjacent:find
。 Please see here for the reference description.请参阅此处以获取参考说明。 Standard is to find equal elements.
标准是找到相等的元素。 But we use our predicate function to find 2 consecutive -1s.
但是我们使用我们的谓词 function 来找到 2 个连续的 -1。
So, the init statement of the for-loop , looks for such a block, starting from the beginning of the container.因此, for-loop的 init 语句从容器的开头开始查找这样的块。 The "condition" of the
for
, checks, if a block could be found or not. for
的“条件”检查是否可以找到一个块。
And the "iteration_expression" looks for the next block, after the first block has been evealuated.并且“迭代表达式”在第一个块被评估之后寻找下一个块。
This is a normal for loop and rather straight forward.这是一个正常的 for 循环,相当直接。
In the loop body, we have only 3 statements:在循环体中,我们只有 3 条语句:
That is all.就这些。 Very simple and compact code.
非常简单紧凑的代码。
At the end we show the gathered results on the console.最后,我们在控制台上显示收集的结果。
That is basically it.基本上就是这样。 Only a few statements needed, because of the reuse of existing functions from the standard C++ library.
由于重用了标准 C++ 库中的现有函数,因此只需要几条语句。
And to show you, how versatile such a function is, you can include
the header vector
and then replace your C-Style arrays simply by:为了向您展示 function 的多功能性,您可以
include
header vector
,然后简单地替换您的 C 样式 arrays:
// Test data
std::vector arr{ 2, 3, -1, -1, -1, 4, -1, -1 };
std::vector<size_t> result(arr.size()/2);
And the program will work as before.该程序将像以前一样工作。
I would strongly recommend to you to start using C++ language elements, if you want to learn C++我强烈建议你开始使用 C++ 语言元素,如果你想学习 C++
In case of questions, please ask.如有问题,请询问。
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int arr[] = { 2, 3, -1, -1, -1, 4, -1, -1 };
int save[4]; // at the worth case we have 4 contiguous ( 4 single -1 )
int counter_of_minus_one=0; // counter of -1 in every contiguous
int counter_of_contiguous=0; // counter of contiguous we have
bool are_we_looking_for_new_contiguous=true; // this mean we are searching for new contiguous
int n=8;
for(int i=0;i<n;i++)
{
if(are_we_looking_for_new_contiguous==true && arr[i]==-1) //this means the -1 we found is our first -1 in our new contiguous
{
counter_of_minus_one++; // +1 for our -1 counter
counter_of_contiguous++; // +1 for our contiguous counter
are_we_looking_for_new_contiguous=false; // so we set flag as false (that means whenever we seen a -1 it's the countinue of current contiguous)
}
else if(are_we_looking_for_new_contiguous==false && arr[i]==-1) // as we said what is flag==false so if we seen -1 it's the countinue of current contiguous
{
counter_of_minus_one++;
}
else if(are_we_looking_for_new_contiguous== false && arr[i]!=-1)//if flag==false but the arr[i] isn't -1 this mean we are out of the -1's contiguous then we close this contiguous and search for a new one
{
save[counter_of_contiguous-1]=counter_of_minus_one; // saving count of -1 for this countiguous
counter_of_minus_one=0; // reset the -1 counter
are_we_looking_for_new_contiguous=true; // looking for new contiguous for next i
}
else if(are_we_looking_for_new_contiguous==true && arr[i]!=-1)// flag==true means we are searching for new contiguous so we just go for next element in array
{
// doing nothing
}
if(i==n-1 && are_we_looking_for_new_contiguous== false && arr[i]==-1) // if the last element be -1 we should add another if seprate of others to just save the last search
{
save[counter_of_contiguous-1]=counter_of_minus_one; // saving count of -1 for this countiguous
}
}
for(int i=0;i<counter_of_contiguous;i++)
{
cout<<save[i]<<endl; //printing result
}
return 0;}
With the range-v3 library you can implement this in a way that is very readable once you're used to this kind of thing.使用 range-v3 库,一旦你习惯了这种东西,你就可以以一种非常易读的方式来实现它。 First write some convenience namespace aliases:
首先写一些方便的命名空间别名:
namespace rs = ranges;
namespace rv = ranges::views;
Now the primary logic that you need to implement is deciding whether a contiguous block of same numbers is valid.现在,您需要实现的主要逻辑是确定相同数字的连续块是否有效。
auto is_valid_block = [](auto block) // block of same numbers
{
return *rs::begin(block) == -1 // containing -1s
and rs::size(block) > 1; // and at least 2 of them
};
Now you can just group the range into blocks of same numbers, and filter those blocks according to your constraint.现在您可以将范围分组为相同数字的块,并根据您的约束过滤这些块。
for (auto block : arr // [ 2 6 6 3 -1 -1 -1 4 -1 -1 5 5 -1 7 ]
| rv::group_by(std::equal_to{}) // [ [2] [6 6] [3] [-1 -1 -1] [4] [-1 -1] [5 5] [-1] [7] ]
| rv::filter(is_valid_block)) // [ [-1 -1 -1] [-1 -1] ]
std::cout << rs::size(block) << " "; // 3 2
Try the following code:试试下面的代码:
int arr[] = { 2, 3, -1, -1, -1, 4, -1, -1};
int curr_cnt = 0;
for(int i = 0; i < 8; i++){
if(arr[i] == -1) curr_cnt++;
else{
if(curr_cnt != 0) cout << curr_cnt << endl;
curr_cnt = 0;
}
}
if(curr_cnt != 0) cout << curr_cnt << endl;
Here we maintain a curr_cnt variable to store the count of consecutive -1s.这里我们维护一个 curr_cnt 变量来存储连续 -1 的计数。 If we get arr[i] as -1 we simply increment this count otherwise set this count to 0, as we have found some other element.
如果我们将 arr[i] 设为 -1,我们只需增加此计数,否则将此计数设置为 0,因为我们找到了其他元素。 But before updating count to zero we can print the value of count if it's greater than 0. Hence, we will get counts of all consecutive -1s.
但是在将 count 更新为零之前,如果它大于 0,我们可以打印 count 的值。因此,我们将获得所有连续 -1 的计数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.