在python中追加意外的列表行为

时间:2016-01-31 10:33:58

标签: python list dictionary recursion append

我正在 Interviewbit 解决这个问题:

给定一组不同的整数S,返回所有可能的子集。子集中的元素必须是非降序。解决方案集不能包含重复的子集。

这是我的简单自解释代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PuzzleGame extends Application {

    private Image image = new Image("http://images.cdn.autocar.co.uk/sites/autocar.co.uk/files/styles/gallery_slide/public/ferrari-laferrari-zfye-059_1.jpg?itok=hfLNxUD9",600,600,false,true);

    private static double SCENE_WIDTH = 1024;
    private static double SCENE_HEIGHT = 768;

    public static int TILE_ROW_COUNT = 5;
    public static int TILE_COLUMN_COUNT = 5;
    public static double TILE_SIZE = 120;

    public static double offsetX = (SCENE_WIDTH - TILE_ROW_COUNT * TILE_SIZE) / 2;
    public static double offsetY = (SCENE_HEIGHT - TILE_COLUMN_COUNT * TILE_SIZE) / 2;

    List<Cell> cells = new ArrayList<>();

    @Override
    public void start(Stage primaryStage) {

        // create grid
        for (int x = 0; x < TILE_ROW_COUNT; x++) {
            for (int y = 0; y < TILE_COLUMN_COUNT; y++) {

                // create tile
                ImageView tile = new ImageView(image);
                Rectangle2D rect = new Rectangle2D(TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE, TILE_SIZE);
                tile.setViewport(rect);

                // consider empty cell, let it remain empty
                if (x == (TILE_ROW_COUNT - 1) && y == (TILE_COLUMN_COUNT - 1)) {
                    tile = null;
                }

                cells.add(new Cell(x, y, tile));
            }
        }

        // shuffle cells
        shuffle();

        // create playfield
        Pane pane = new Pane();

        // put tiles on playfield, assign event handler
        for (int i = 0; i < cells.size(); i++) {

            Cell cell = cells.get(i);

            Node imageView = cell.getImageView();

            // consider empty cell
            if (imageView == null)
                continue;

            // click-handler: swap tiles, check if puzzle is solved
            imageView.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseEvent -> {

                moveCell((Node) mouseEvent.getSource());

            });

            // position images on scene
            imageView.relocate(cell.getLayoutX(), cell.getLayoutY());

            pane.getChildren().add(cell.getImageView());
        }

        Scene scene = new Scene(pane, SCENE_WIDTH, SCENE_HEIGHT);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    /**
     * Swap images of cells randomly
     */
    public void shuffle() {

        Random rnd = new Random();

        for (int i = 0; i < 1000; i++) {

            int a = rnd.nextInt(cells.size());
            int b = rnd.nextInt(cells.size());

            if (a == b)
                continue;

            // skip bottom right cell swap, we want the empty cell to remain there
            if( cells.get(a).isEmpty() || cells.get(b).isEmpty())
                continue;

            swap( cells.get(a), cells.get(b));

        }

    }

    public void swap( Cell cellA, Cell cellB) {

        ImageView tmp = cellA.getImageView();
        cellA.setImageView(cellB.getImageView());
        cellB.setImageView(tmp);

    }

    public boolean checkSolved() {

        boolean allSolved = true;

        for (Cell cell : cells) {

            if (!cell.isSolved()) {
                allSolved = false;
                break;
            }
        }

        System.out.println("Solved: " + allSolved);

        return allSolved;
    }

    public void moveCell(Node node) {

        // get current cell using the selected node (imageview)
        Cell currentCell = null;
        for (Cell tmpCell : cells) {
            if (tmpCell.getImageView() == node) {
                currentCell = tmpCell;
                break;
            }
        }

        if (currentCell == null)
            return;

        // get empty cell
        Cell emptyCell = null;

        for (Cell tmpCell : cells) {
            if (tmpCell.isEmpty()) {
                emptyCell = tmpCell;
                break;
            }
        }

        if (emptyCell == null)
            return;

        // check if cells are swappable: neighbor distance either x or y must be 1 for a valid move
        int steps = Math.abs(currentCell.x - emptyCell.x) + Math.abs(currentCell.y - emptyCell.y);
        if (steps != 1)
            return;

        System.out.println("Transition: " + currentCell + " -> " + emptyCell);

        // cells are swappable => create path transition
        Path path = new Path();
        path.getElements().add(new MoveToAbs(currentCell.getImageView(), currentCell.getLayoutX(), currentCell.getLayoutY()));
        path.getElements().add(new LineToAbs(currentCell.getImageView(), emptyCell.getLayoutX(), emptyCell.getLayoutY()));

        PathTransition pathTransition = new PathTransition();
        pathTransition.setDuration(Duration.millis(100));
        pathTransition.setNode(currentCell.getImageView());
        pathTransition.setPath(path);
        pathTransition.setOrientation(PathTransition.OrientationType.NONE);
        pathTransition.setCycleCount(1);
        pathTransition.setAutoReverse(false);

        final Cell cellA = currentCell;
        final Cell cellB = emptyCell;
        pathTransition.setOnFinished(actionEvent -> {

            swap( cellA, cellB);

            checkSolved();

        });

        pathTransition.play();

    }

    private static class Cell {

        int x;
        int y;

        ImageView initialImageView;
        ImageView currentImageView;

        public Cell(int x, int y, ImageView initialImageView) {
            super();
            this.x = x;
            this.y = y;
            this.initialImageView = initialImageView;
            this.currentImageView = initialImageView;
        }

        public double getLayoutX() {
            return x * TILE_SIZE + offsetX;
        }

        public double getLayoutY() {
            return y * TILE_SIZE + offsetY;
        }

        public ImageView getImageView() {
            return currentImageView;
        }

        public void setImageView(ImageView imageView) {
            this.currentImageView = imageView;
        }

        public boolean isEmpty() {
            return currentImageView == null;
        }

        public boolean isSolved() {
            return this.initialImageView == currentImageView;
        }

        public String toString() {
            return "[" + x + "," + y + "]";
        }

    }

    // absolute (layoutX/Y) transitions using the pathtransition for MoveTo
    public static class MoveToAbs extends MoveTo {

        public MoveToAbs(Node node) {
            super(node.getLayoutBounds().getWidth() / 2, node.getLayoutBounds().getHeight() / 2);
        }

        public MoveToAbs(Node node, double x, double y) {
            super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
        }

    }

    // absolute (layoutX/Y) transitions using the pathtransition for LineTo
    public static class LineToAbs extends LineTo {

        public LineToAbs(Node node, double x, double y) {
            super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

这是输出:

ans_list=[]

def solve(i,a,tmp,l,k):
    global ans_list
    if i==l :
      print "List to append:     " ,tmp
      ans_list.append(tmp) 
      print "ans_list currently: ", ans_list
      return

    j=k
    while j < len(a):
      tmp.append(a[j])
      solve(i+1,a,tmp,l,j+1)
      tmp.pop()
      j+=1


class Solution:
    # @param a : list of integers
    # @return a list of list of integers
    def subsets(self, a):
      a=sorted(a)
      global ans_list
      tmp=[]
      i=0
      for l in range(len(a)+1):
        solve(0,a,tmp,l,0)
      return ans_list

def main():
  a=[1,2,3]
  ob=Solution()
  li=ob.subsets(a)
  print "Ans:" ,li

if __name__ == '__main__':
    main()

我甚至尝试将List to append: [] Current ans_list: [[]] List to append: [1] Current ans_list: [[1], [1]] List to append: [2] Current ans_list: [[2], [2], [2]] List to append: [3] Current ans_list: [[3], [3], [3], [3]] List to append: [1, 2] Current ans_list: [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] List to append: [1, 3] Current ans_list: [[1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3]] List to append: [2, 3] Current ans_list: [[2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3]] List to append: [1, 2, 3] Current ans_list: [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]] Ans: [[], [], [], [], [], [], [], []] 作为参数而不是全局变量传递,但结果是相同的。甚至尝试使用字典而不是列表列表,但它会导致相同的行为。然而,我注意到一件有趣的事情是当我在ans_list函数中将ans_list.append(tmp)更改为ans_list.extend(tmp)时输出变为:

solve

这是非常期待的。现在我不确定在python中附加列表和字典会出现这种意外行为的原因是什么,而extend会给出正确的响应。任何帮助将不胜感激。

我是python的新手并使用Python 2.7.10

1 个答案:

答案 0 :(得分:1)

问题是你在子集()的循环外创建了 tmp 。现在 resolve() tmp 的每次使用都将指向同一个列表,并且将对ans_list中的每个元素执行每个操作,包括pop()。

有很多方法可以解决此问题,但如果您想要最少的代码更改,只需导入复制模块并更改:

ans_list.append(tmp) 

为:

ans_list.append(copy.deepcopy(tmp))

编辑(我的解决方案):

ans = set()
for i in range(len(a)+1):
    for j in range(len(a)+1):
        ans.add(tuple(a[i:j]))