如何以逆时针方式循环2D阵列?

时间:2018-10-11 15:56:20

标签: javascript arrays ruby loops multidimensional-array

给定一个二维的m x n数组,如何以逆时针方式遍历它们?

例如:

// ./~/detect-private-browsing/index.js

function retry(isDone, next) {
    var current_trial = 0, max_retry = 50, interval = 10, is_timeout = false;
    var id = window.setInterval(
        function() {
            if (isDone()) {
                window.clearInterval(id);
                next(is_timeout);
            }
            if (current_trial++ > max_retry) {
                window.clearInterval(id);
                is_timeout = true;
                next(is_timeout);
            }
        },
        10
    );
}

function isIE10OrLater(user_agent) {
    var ua = user_agent.toLowerCase();
    if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) {
        return false;
    }
    var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua);
    if (match && parseInt(match[1], 10) >= 10) {
        return true;
    }
    // MS Edge Detection from this gist: https://gist.github.com/cou929/7973956
    var edge = /edge/.exec(ua); 
    if (edge && edge[0] == "edge") { 
        return true; 
    }
    return false;
}

module.exports = {
    detectPrivateMode: function(callback) {
        var is_private;

        if (window.webkitRequestFileSystem) {
            window.webkitRequestFileSystem(
                window.TEMPORARY, 1,
                function() {
                    is_private = false;
                },
                function(e) {
                    console.log(e);
                    is_private = true;
                }
            );
        } else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) {
            var db;
            try {
                db = window.indexedDB.open('test');
            } catch(e) {
                is_private = true;
            }

            if (typeof is_private === 'undefined') {
                retry(
                    function isDone() {
                        return db.readyState === 'done' ? true : false;
                    },
                    function next(is_timeout) {
                        if (!is_timeout) {
                            is_private = db.result ? false : true;
                        }
                    }
                );
            }
        } else if (isIE10OrLater(window.navigator.userAgent)) {
            is_private = false;
            try {
                if (!window.indexedDB) {
                    is_private = true;
                }                 
            } catch (e) {
                is_private = true;
            }
        } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {

            // One-off check for weird sports 2.0 polyfill
            // This also impacts iOS Firefox and Chrome (newer versions), apparently
            // @see bglobe-js/containers/App.js:116
            if (window.safariIncognito) {
                is_private = true;
            } else {
                        try {
                           window.openDatabase(null, null, null, null);
                        } catch (e) {
                           is_private = true;
                        }

                try {
                    window.localStorage.setItem('test', 1);
                } catch(e) {
                    is_private = true;
                }
            } 

            if (typeof is_private === 'undefined') {
                is_private = false;
                window.localStorage.removeItem('test');
            }
        }



        retry(
            function isDone() {
                return typeof is_private !== 'undefined' ? true : false;
            },
            function next(is_timeout) {
                callback(is_private);
            }
        );
    }
};

我真的不介意是用ruby还是js给出实现

我当前的解决方案是这样的:

matrix = [
  [   1,    2,   3,    4  ],
  [   5,    6,   7,    8  ],
  [   9,   10,  11,   12  ],
  [  13,   14,  15,   16  ]
]

1st loop: 1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2
2nd loop: 6, 10, 11, 7, 6

更新

只要格式正确,输出就不会格式化。

问题的原因

此问题的目的是逆时针逐层遍历这些数组,直到没有更多层为止。对于每个遍历,我们将值逆时针移动。例如:

  (1..rotate).each do
    bottom_left_corner = i
    top_right_corner   = j
    start_nth_layer = 1; end_nth_layer = matrix.length - 2
    matrix.reverse_each do
      matrix[bottom_left_corner].unshift(matrix[bottom_left_corner - 1].shift) if bottom_left_corner > 0
      matrix[top_right_corner] << matrix[top_right_corner + 1].pop if top_right_corner < matrix.length - 1

      bottom_left_corner -= 1; top_right_corner += 1
    end

    nth_layer(matrix, start_nth_layer, end_nth_layer)

  end

6 个答案:

答案 0 :(得分:0)

这是矩阵图层旋转问题。这是我的完整解决方案:

function matrixRotation(matrix, rotate) {
    var r = matrix.length, c = matrix[0].length;
    var depth = Math.min(r,c)/2;
    for(var i=0;i<depth;i++) {
        var x = i, y = i, n = (r-i*2 - 2)*2 + (c-i*2-2)*2+4, dir = 'down', index=0;
        var buf = [];
        while(index < n) {
            buf.push(matrix[x][y]);
            if(dir == 'down') {
                if(x+1 >= r-i) {
                    dir = 'right';
                    y++;
                } else {
                    x++;
                }
            } else if(dir == 'right') {
                if(y+1 >= c-i) {
                    dir = 'up';
                    x--;
                } else {
                    y++;
                }
            } else if(dir == 'up') {
                if(x-1 <= i-1) {
                    dir = 'left';
                    y--;
                } else {
                    x--;
                }
            } else if(dir == 'left') {
                y--;
            }
            index++;
        }
        var move = rotate%n;
        buf = [...buf.slice(buf.length-move), ...buf.slice(0, buf.length-move)]
        x = i, y = i, dir = 'down', index = 0;
        while(index < n) {
            matrix[x][y] = buf[index];
            if(dir == 'down') {
                if(x+1 >= r-i) {
                    dir = 'right';
                    y++;
                } else {
                    x++;
                }
            } else if(dir == 'right') {
                if(y+1 >= c-i) {
                    dir = 'up';
                    x--;
                } else {
                    y++;
                }
            } else if(dir == 'up') {
                if(x-1 <= i-1) {
                    dir = 'left';
                    y--;
                } else {
                    x--;
                }
            } else if(dir == 'left') {
                y--;
            }
            index++;
        }
    }
    matrix.map(row => console.log(row.join(' ')));
}

const matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
// rotate count
const r = 3

matrixRotation(matrix, r);

答案 1 :(得分:0)

此方法应支持matrixmatrix[n]的任何大小。如果适合您,请尝试使用各种测试用例。

请注意,这里我忽略了任何性能缺陷。

var arr = [
  [   1,    2,   3,    4  ],
  [   5,    6,   7,    8  ],
  [   9,   10,  11,   12  ],
  [  13,   14,  15,   16  ]
],
result = [];

while ( arr.flat().length ) {
  var res = [];

  // 1. Left side
  arr.forEach(x => res = res.concat( x.splice(0, 1) ));

  // 2. Bottom side
  if (arr.length) {
    res = res.concat( ...arr.splice(arr.length - 1, 1) );
  }

  // 3. Right side
  var tmp = [];
  if (arr.flat().length) {
    arr.forEach(x => tmp.push( x.splice(arr.length - 1, 1) ));
    res = res.concat( ...tmp.reverse() );
  }

  // 4. Top side
  if (arr.length) {
    tmp = [].concat( ...arr.splice(0, 1) );
    res = res.concat( tmp.reverse() );
  }

  result.push(res);
}

console.log(result);

答案 2 :(得分:0)

我将以分层的方式编写此代码,编写矩阵转置逻辑(即在西北偏南对角线上翻转矩阵),并使用该代码和简单的reverse来建立矩阵的逆时针旋转矩阵,使用该旋转来建立顺时针螺旋,最后再次在顺时针螺旋旁边使用transpose来建立逆时针螺旋。

我之所以选择此顺序,是因为通常更需要顺时针螺旋,但是直接构建逆时针螺旋将很容易。 提示rotateClockwise = m => transpose(reverse(m))

const reverse = a => [...a].reverse();
const transpose = m => m[0].map((c, i) => m.map(r => r[i]))
const rotateCounter = m => reverse(transpose(m))
const spiralClockwise = m => m.length < 2
  ? m[0]
  : m[0].concat(spiralClockwise(rotateCounter(m.slice(1))))
const spiralCounter = m => spiralClockwise(transpose(m))

console.log(spiralCounter([
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
]))

请注意,这里的中间函数本身很有可能有用。因此,这是解决该问题的好方法。

答案 3 :(得分:0)

给出数组:

array = 
  [
    [ '00', '01', '02', '03', '04', '05'],
    [ '10', '11', '12', '13', '14', '15'],
    [ '20', '21', '22', '23', '24', '25'],
    [ '30', '31', '32', '33', '34', '35']
  ]

这将返回外部循环:

external_ccw_round = [array.map(&:shift), array.pop, array.map(&:pop).reverse, array.shift.reverse].flatten
#=> ["00", "10", "20", "30", "31", "32", "33", "34", "35", "25", "15", "05", "04", "03", "02", "01"]

只留下核心

array #=> [["11", "12", "13", "14"], ["21", "22", "23", "24"]]

对于多于一行的矩阵。

这是一种具有递归实现的方法

适用于任何二维矩阵。

def ccw_scan(array, result=[])
  return array if array.size <= 1
  result << [array.map(&:shift), array.pop, array.map(&:pop).reverse, array.shift.reverse]
  if array.size >= 2
    then ccw_scan(array, result)
  else result << array
  end
  result.flatten.compact
end

在数组上调用方法:

ccw_scan(array)
#=> ["00", "10", "20", "30", "31", "32", "33", "34", "35", "25", "15", "05", "04", "03", "02", "01", "11", "21", "22", "23", "24", "14", "13", "12"]

答案 4 :(得分:0)

这就是我用红宝石处理的方式:

def counter_clockwise!(arr)
  return arr if arr.size <= 1
  rotation = [
    arr.map(&:shift)
      .concat(arr.pop,
              arr.map(&:pop).reverse,
              arr.shift.reverse).compact
  ]
  rotation.push(*send(__method__,arr)) unless arr.all?(&:empty?)
  rotation 
end

def counter_clockwise(arr)
  counter_clockwise!(arr.map(&:dup))
end

示例:

arr = [
  [   1,    2,   3,    4  ],
  [   5,    6,   7,    8  ],
  [   9,   10,  11,   12  ],
  [  13,   14,  15,   16  ],
  [  17,   18,  19,   20  ],
  [  21,   22,  23,   24  ]
]
counter_clockwise(arr)
#=> [[1, 5, 9, 13, 17, 21, 22, 23, 24, 20, 16, 12, 8, 4, 2, 3], 
#    [6, 10, 14, 18, 19, 15, 11, 7]]

此方法将外部边缘递归处理为组(原始帖子中的“循环”)。显然,如果只希望没有组的逆时针螺旋,则可以使返回值变平。

这还将处理非M x N个矩阵,例如:

arr = [
  [   1,    2,   3,    4  , 72 ],
  [   5,    6,   7,    8  , 73 ],
  [   9,   10,        11  , 12 ],
  [  13,   14,        16  , 75 ],
  [  17,   18,  19,   20  , 76 ],
  [  21,   22,  23,   24  , 77 ]
]

counter_clockwise(arr) 
#=> [[1, 5, 9, 13, 17, 21, 22, 23, 24, 77, 76, 75, 12, 73, 72, 4, 3, 2],       
#   [6, 10, 14, 18, 19, 20, 16, 11, 8, 7]]

如果您希望每个边缘都可以保证M x N,那么这也将起作用

def counter_clockwise_edges(arr)
  return arr if arr.size == 1
  arr = arr.transpose
  [arr.shift].push(*send(__method__,arr.map(&:reverse))) 
end
counter_clockwise_edges(arr)
#=> [[1, 5, 9, 13, 17, 21], 
     [22, 23, 24], 
     [20, 16, 12, 8, 4], 
     [3, 2], 
     [6, 10, 14, 18], 
     [19, 15, 11, 7]]

答案 5 :(得分:0)

以下是我对this SO question的回答的一种修改,与之不同之处仅在于数组沿相反的方向遍历。

arr = matrix.map(&:dup).transpose
  #=> [[1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]]

步骤如下。

matrix

我对out = [] out = out + arr.shift #=> [1, 5, 9, 13] arr #=> [[2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]] arr = arr.transpose.reverse #=> [[14, 15, 16], [10, 11, 12], [6, 7, 8], [2, 3, 4]] out = out + arr.shift #=> [1, 5, 9, 13, 14, 15, 16] arr #=> [[10, 11, 12], [6, 7, 8], [2, 3, 4]] arr = arr.transpose.reverse #=> [[12, 8, 4], [11, 7, 3], [10, 6, 2]] out = out + arr.shift #=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4] arr #=> [[11, 7, 3], [10, 6, 2]] arr = arr.transpose.reverse #=> [[3, 2], [7, 6], [11, 10]] out = out + arr.shift #=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2] arr #=> [[7, 6], [11, 10]] 的元素进行了欺骗,以使后者不会被突变。

arr = arr.transpose.reverse
  #=> [[6, 10], [7, 11]]
out = out + arr.shift
  #=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10]
arr
  #=> [[7, 11]]

arr = arr.transpose.reverse
  #=> [[11], [7]]
out = out + arr.shift
  #=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11]
arr
  #=> [[7]]

arr = arr.transpose.reverse
  #=> [[7]]
out = out + arr.shift
  #=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11, 7]
arr
  #=> []

arr

由于break现在为空,我们out返回arr arr = arr.transpose.reverse out = out + arr.shift arr arr = arr.transpose.reverse out = out + arr.shift arr arr = arr.transpose.reverse out = out + arr.shift arr arr = arr.transpose.reverse out = out + arr.shift arr arr = arr.transpose.reverse out = out + arr.shift arr arr = arr.transpose.reverse

from tkinter import*

import tkinter as tk

class QueueApp(tk.Tk):
    def __init__(self):
    super().__init__()
    self.title(' Queue')
    self.minsize(200, 200)
    self.x=0
    self.frame1=tk.Frame(self)
    self.frame1.place(x=0,y=0,width=70,height=170,anchor='nw')
    self.frame2=tk.Frame(self)
    self.frame2.place(x=40,y=175,anchor='nw')
    self.frame3 = tk.Frame(self)
    self.frame3.place(x=100, y=0, width=50, height=170, anchor='nw')
    add=tk.Button(self.frame2,text='add',command=self.add_text)
    add.pack()

def add_text(self):
    self.x=self.x+1
    self.text=tk.Label(self.frame1,text=self.x)
    self.text.pack(side=tk.TOP)


  self.delete_button=tk.Button(self.frame3,text='delete',
  command=self.delete)
    self.delete_button.pack(side=tk.TOP)

def delete(self):
    self.text.destroy()
    self.delete_button.destroy()


if __name__=='__main__':
    app = QueueApp()
    app.mainloop()