【问题标题】:A question about matrix manipulation关于矩阵操作的问题
【发布时间】:2011-06-09 01:24:39
【问题描述】:

给定一个 1*N 矩阵或数组,我如何找到具有相同值的前 4 个元素,然后存储这些元素的索引?

PS: 我只是好奇。如果我们想找到值差异在一定范围内的前 4 个元素,比如低于 2,该怎么办?例如,M=[10,15,14.5,9,15.1,8.5,15.5,9.5],我要查找的元素是 15,14.5,15.1,15.5,索引是 2,3,5, 7.

【问题讨论】:

  • 前 4 个具有值的元素是什么意思? ...您所说的索引到底是什么意思?
  • 嗨,穆尔基。感谢您指出了这一点。我又修改了问题。
  • 我不明白这个问题。也许我的英语还不够。 “存储这些元素的索引”是什么意思?我们应该返回索引?
  • 你改变了什么?我仍然无法理解您的问题...请您补充详细信息...
  • 您最近编辑的示例令人困惑。 4 不应该是第一个重复 4 次的值,而不是 5?

标签: arrays algorithm matlab indexing matrix


【解决方案1】:

这是我的 MATLAB 解决方案:

array = randi(5, [1 10]);            %# random array of integers

n = unique(array)';                  %'# unique elements
[r,~] = find(cumsum(bsxfun(@eq,array,n),2) == 4, 1, 'first');
if isempty(r)
    val = []; ind = [];              %# no answer
else
    val = n(r);                      %# the value found
    ind = find(array == val, 4);     %# indices of elements corresponding to val
end

例子:

array =
     1     5     3     3     1     5     4     2     3     3
val =
     3
ind =
     3     4     9    10

说明:

首先,我们提取唯一元素列表。在上面使用的示例中,我们有:

n =
     1
     2
     3
     4
     5

然后使用 BSXFUN 函数,我们将每个唯一值与我们拥有的整个向量数组进行比较。这相当于以下内容:

result = zeros(length(n),length(array));
for i=1:length(n)
    result(i,:) = (array == n(i));        %# row-by-row
end

继续我们得到的相同示例:

result =
     1     0     0     0     1     0     0     0     0     0
     0     0     0     0     0     0     0     1     0     0
     0     0     1     1     0     0     0     0     1     1
     0     0     0     0     0     0     1     0     0     0
     0     1     0     0     0     1     0     0     0     0

接下来,我们在 result 矩阵上调用 CUMSUM 来计算沿行的累积和。每行都会告诉我们该元素到目前为止出现了多少次:

>> cumsum(result,2)
ans =
     1     1     1     1     2     2     2     2     2     2
     0     0     0     0     0     0     0     1     1     1
     0     0     1     2     2     2     2     2     3     4
     0     0     0     0     0     0     1     1     1     1
     0     1     1     1     1     2     2     2     2     2

然后我们将它与四个cumsum(result,2)==4 进行比较(因为我们想要一个元素第四次出现的位置):

>> cumsum(result,2)==4
ans =
     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     1
     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0

最后我们调用FIND按照列顺序查找第一个出现的1:如果我们逐列遍历上一步的矩阵,那么第一个出现1的行表示我们正在寻找的元素的索引。在本例中,它是第三行 (r=3),因此唯一向量中的第三个元素是答案 val = n(r)。请注意,如果我们在原始数组中有多个元素重复 4 次或更多次,那么第一次出现第四次的元素将首先显示为 1 在上述表达式中逐列显示。

查找对应答案值的索引是对 FIND 的简单调用...

【讨论】:

  • 不错!第一个很好地使用 bsxfun 的无环解决方案。好东西。
  • 感谢您的代码,Amro!但我只能为这个问题打勾。虽然我是 Matlab 的新手,并不能真正理解 bsxfun 的魔力,但从其他人的 cmets 中我可以看到它是一个非常好的算法。非常感谢您的帮助!
  • 非常感谢您解释所有这些!我现在清楚多了!
【解决方案2】:

你的 PS 问题更复杂。我没有时间检查每个案例,但想法就在这里:

M=[10,15,14.5,9,15.1,8.5,15.5,9.5]
val = NaN;
num_min = 4;
delta = 2;
[Ms, iMs] = sort(M);
dMs = diff(Ms);
ind_min=Inf;
n = 0;
for i = 1:length(dMs)
    if dMs(i) <= delta
    n=n+1;
    else
    n=0;
    end
    if n == (num_min-1)
        if (iMs(i) < ind_min)
            ind_min = iMs(i);
        end
    end
end
ind = sort(iMs(ind_min + (0:num_min-1)))
val = M(ind)

【讨论】:

  • 嗨克莱门特。感谢您的解决方案!但是您能否进一步解释一下这部分 - if(iMs(i)
  • 在 iMs(已排序 M 的索引)中,索引不是严格升序的(但对应的值是升序的)。因此,当您在区间中找到 4 个元素时,您必须检查它们的原始索引是否是超出 4 个可接受值组的最小的。
  • 感谢克莱门特的解释!现在我明白了。
【解决方案3】:

由于有些解决方案我不太容易理解,所以我做了一个:

l = 10; m = 5; array = randi(m, [1 l])

A = zeros(l,m);    % m is the maximum value (may) in array
A(sub2ind([l,m],1:l,array)) = 1;
s = sum(A,1);
b = find(s(array) == 4,1); 
% now in b is the index of the first element

if (~isempty(b)) 
    find(array == array(b))
else 
    disp('nothing found'); 
end

我发现这更容易可视化。它在方阵的所有位置填充“1”,其中存在数组中的值 - 根据它们的位置(行)和值(列)。这很容易总结并映射到原始数组。缺点:如果数组包含非常大的值,A 也可能变得相对较大。

【讨论】:

  • 感谢您的回答,user492238!
【解决方案4】:

忽略这一点并使用 Amro 的强大解决方案。 . .

这是我在 Matlab 中的做法。矩阵可以是任意大小并包含任意范围的值,这应该有效。此解决方案将自动找到一个值,然后是前 4 个元素的索引,而无需先验地输入搜索值。

tab = [2 5 4 5 4 6 4 5 5 4 6 9 5 5]

%this is a loop to find the indicies of groups of 4 identical elements
tot = zeros(size(tab));
for nn = 1:numel(tab)
    idxs=find(tab == tab(nn), 4, 'first');
    if numel(idxs)<4
        tot(nn) = Inf;
    else
        tot(nn) = sum(idxs);
    end        
end

%find the first 4 identical
bestTot = find(tot == min(tot), 1, 'first' );

%store the indicies you are interested in.
indiciesOfInterst = find(tab == tab(bestTot), 4, 'first')

【讨论】:

  • 几个cmets:可以使用randi生成随机整数列表。此外,当您计算重复次数时,您当前是在汇总索引,而不是计数,并且即使少于四个,您也在汇总它们,因此您不太可能得到正确的结果。
  • 只是在测试了克莱门特的修改后的代码之后修复了 小于 4 的问题,然后意识到我的解决方案也被破坏了。为有关兰迪的单挑欢呼。通过修订,克莱门特的解决方案 > 我的。
【解决方案5】:

如果您希望第一个值在 Matlab 中的数组 'tab' 中出现 4 次,您可以使用

num_min = 4
val=NaN;
for i = tab
    if sum(tab==i) >= num_min
        val = i;
        break
    end
end
ind = find(tab==val, num_min);

通过实例与

tab = [2 4 4 5 4 6 4 5 5 4 6 9 5 5]

你得到

val =
     4
ind =
     2     3     5     7

【讨论】:

  • 您应该将sum 语句编写为:if sum(tab==i)&gt;=num_min。目前它对值求和,所以如果数组的第一个元素是 9,它只出现一次,就会被选中。
  • 另外,您应该在开始循环之前将 val 设置为 NaN - 如果没有重复至少 4 次的值,则会在最后一行出现错误,因为 val不会被定义。
  • 感谢您的帮助。您使用的算法清晰易懂。
【解决方案6】:

这里是 C++ 代码

std::map<int,std::vector<int> > dict;

std::vector<int> ans(4);//here we will store indexes
bool noanswer=true;

//my_vector is a vector, which we must analize
for(int i=0;i<my_vector.size();++i)
{
    std::vector<int> &temp = dict[my_vector[i]];
    temp.push_back(i);
    if(temp.size()==4)//we find ans
    {
         std::copy(temp.begin(),temp.end(),ans.begin() );
         noanswer = false;
         break;
    }   
}
if(noanswer)
   std::cout<<"No Answer!"<<std::endl;

【讨论】:

  • 感谢您的回答,Ashot Martirosyan!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多