【问题标题】:How to change the position of an array element?如何改变数组元素的位置?
【发布时间】:2011-01-19 10:05:06
【问题描述】:

我有一个关于如何更改数组元素的索引的问题,这样它就不会出现在第 7 位,而是在第 2 位...

有处理这个的函数吗?

【问题讨论】:

    标签: ruby arrays


    【解决方案1】:

    没有比这更简单的了:

    array.insert(2, array.delete_at(7))
    

    【讨论】:

    • 好的,现在反向。位置 2 到位置 7。也许没有你想的那么简单。
    • 如果您从要插入的索引之前的索引移动,这将不起作用!删除操作将发生在插入之前,因此您需要在插入之前考虑元素的移动。
    • 上述cmets是错误的,这种方法在所有情况下都有效。在 irb 中自己尝试一下。
    • 这个答案具有误导性。虽然它有效并回答了问题,但@wizzard 是正确的,因为它并非在所有情况下都有效。请参阅下面的答案,了解在源索引小于目标索引的情况下有效的方法。
    【解决方案2】:
    irb> a = [2,5,4,6]
    => [2, 5, 4, 6]
    irb> a.insert(1,a.delete_at(3))
    => [2, 6, 5, 4]
    

    【讨论】:

    • 感谢您的正确回答。我给了trekd正确的答案,因为他还有新手奖金。
    【解决方案3】:

    初学者说明

    这些答案很棒。我一直在寻找有关这些答案如何工作的更多解释。以下是上述答案中发生的情况、如何​​按值切换元素以及文档链接。

    # sample array
    arr = ["a", "b", "c", "d", "e", "f", "g", "h"]
    
    # suppose we want to move "h" element in position 7 to position 2 (trekd's answer)
    arr = arr.insert(2, arr.delete_at(7))
    => ["a", "b", "h", "c", "d", "e", "f", "g"]
    

    这是因为arr.delete_at(index) 删除了指定索引处的元素(在我们上面的示例中为“7”),并返回该索引中的值。因此,运行 arr.delete_at(7) 会产生:

    # returns the deleted element
    arr.delete_at(7) 
    => "h"           
    
    # array without "h"
    arr
    => ["a", "b", "c", "d", "e", "f", "g"]
    

    把它们放在一起,insert 方法现在将把这个“h”元素放在位置 2。为了清楚起见,把它分成两个步骤:

    # delete the element in position 7
    element = arr.delete_at(7)  # "h"
    arr.insert(2, element)
    => ["a", "b", "h", "c", "d", "e", "f", "g"]
    

    按值切换元素

    假设您想将数组中值为“h”的元素移动到位置 2,而不管其位置如何。这可以通过 index 方法轻松完成:

    arr = arr.insert(2, arr.delete_at( arr.index("h") ))
    

    注意:以上假设数组中只有一个“h”值。

    文档

    【讨论】:

    • 按值切换元素 -> 如果你有更多的 "h" 怎么办
    • @AdamLudian 您只需要具体说明您想要的行为。例如,如果您的数组有多个“h”值,那么您可能根本不想运行此代码。
    【解决方案4】:

    如果你想交换最好的方法:

    array = [4, 5, 6, 7]
    
    array[0], array[3] = array[3], array[0]
    
    array # => [7, 5, 6, 4]
    

    【讨论】:

    • 虽然很整洁,但这交换了两个位置,这不是原始发布者所要求的。他们想将第 7 项移至第 2 项。所以从技术上讲,这并不能回答问题。
    【解决方案5】:

    如果您不关心数组中其他元素的位置,您可以使用 .rotate! (请注意,此方法末尾的 ! 会更改实际数组)方法。

    arr = [1, 2, 3, 4, 5, 6, 7, 8]
    arr.rotate! -3
    arr = [6, 7, 8, 1, 2, 3, 4, 5]
    

    这会获取位于索引 7 处的元素 8,并将其旋转到索引 2。

    【讨论】:

      【解决方案6】:

      此处的答案并未涵盖两种可能的情况。虽然该问题处理的origin 索引高于destination,但如果相反,则以下解决方案将不起作用:

      array.insert 7, array.delete_at(2)
      

      这是因为删除 2 处的值会使数组中的所有内容(大于 2)向下移动 1。现在我们的目标索引 7 指向以前的索引 8。

      要解决这个问题,我们需要检查origin 是否小于destination,如果是,则从destination 中减去1。

      origin = 2
      destination = 7
      
      destination -= 1 if origin < destination
      array.insert destination, array.delete_at(origin)
      

      【讨论】:

        【解决方案7】:

        不更好用:

        irb> a = [2,5,4,6]
        #=> [2, 5, 4, 6]
        irb> a.insert(1, a.pop)
        #=> [2, 6, 5, 4]
        

        ?

        【讨论】:

        • 这仅在您想移动最后一个元素时有效,但如果您想移动另一个元素则无效:)
        【解决方案8】:

        如果您正在寻找在数组中上下移动 uniq 项的解决方案:

        module ArrayElementMove
          MustBeUniqArray = Class.new(StandardError)
          ItemNotInArray  = Class.new(StandardError)
        
          def self.up!(array, item)
            self.check_if_uniq!(array)
            return array if array.first == item
            position = array.index(item) || raise(ItemNotInArray)
            array.insert((position - 1), array.delete_at(position))
          end
        
          def self.down!(array, item)
            self.check_if_uniq!(array)
            return array if array.last == item
            position = array.index(item) || raise(ItemNotInArray)
            array.insert((position + 1), array.delete_at(position))
          end
        
          def self.check_if_uniq!(array)
            raise MustBeUniqArray if array.size != array.uniq.size
          end
        end
        

        规格:

        require 'spec_helper'
        
        RSpec.describe ArrayElementMove do
          let(:arr) { [1,2,3,4,5,6] }
        
          it do
            ArrayElementMove.up!(arr, 4)
            expect(arr).to eq([1,2,4,3,5,6])
        
            expect(ArrayElementMove.up!(arr, 4).to eq([1,4,2,3,5,6])
            expect(arr).to eq([1,4,2,3,5,6])
        
            ArrayElementMove.up!(arr, 4)
            expect(arr).to eq([4,1,2,3,5,6])
        
            ArrayElementMove.up!(arr, 4)
            expect(arr).to eq([4,1,2,3,5,6])
          end
        
          it do
            ArrayElementMove.down!(arr, 4)
            expect(arr).to eq([1,2,3,5,4,6])
        
            expect(ArrayElementMove.down!(arr, 4)).to eq([1,2,3,5,6,4])
            expect(arr).to eq([1,2,3,5,6,4])
        
            expect(ArrayElementMove.down!(arr, 4)).to eq([1,2,3,5,6,4])
            expect(arr).to eq([1,2,3,5,6,4])
          end
        
          context 'when non uniq array' do
            let(:arr) { [1,4,2,3,4,5,6] }
        
            it do
              expect { ArrayElementMove.down!(arr, 3) }.to raise_exception(ArrayElementMove::MustBeUniqArray)
              expect(arr).to eq([1,4,2,3,4,5,6])
            end
        
            it do
              expect { ArrayElementMove.down!(arr, 3) }.to raise_exception(ArrayElementMove::MustBeUniqArray)
              expect(arr).to eq([1,4,2,3,4,5,6])
            end
          end
        
          context 'when non existing item' do
            it do
              expect { ArrayElementMove.up!(arr, 9) }.to raise_exception(ArrayElementMove::ItemNotInArray)
              expect(arr).to eq([1,2,3,4,5,6])
            end
        
            it do
              expect { ArrayElementMove.up!(arr, 9) }.to raise_exception(ArrayElementMove::ItemNotInArray)
              expect(arr).to eq([1,2,3,4,5,6])
            end
          end
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-09-21
          • 1970-01-01
          • 2018-10-22
          • 2012-09-03
          • 1970-01-01
          • 2017-02-18
          • 1970-01-01
          相关资源
          最近更新 更多