首页 > 解决方案 > sortOn():试图对一个数组的副本进行排序,但原来的也在排序中

问题描述

我正在尝试对数组的副本进行排序,但由于某种原因,两个数组都正在排序。这可能是什么原因造成的?

var myArray = [["stuff," "stuff"], ["stuff", "stuff"]]
var myArrayCopy = myArray as Array

trace(myArray) //Gives unsorted array
trace(myArrayCopy) //Gives unsorted array

arrayCopy.sortOn(1, Array.CASEINSENSITIVE)

trace(myArray) //Gives sorted array
trace(myArrayCopy) //Gives sorted array

标签: arrayssortingactionscript-3

解决方案


简单地说,在 AS3 中有两种类型的数据:原始数据(intuintNumberBooleanString)和对象(其他所有数据,甚至是基本的ObjectArray类型)。原始数据按其值复制:

var a:int = 1;
var b:int;

// Now we pass the value of a.
b = a;
a = 2;

trace(a); // output: 2
trace(b); // output: 1

然后,所有对象都通过它们的引用传递(就像 C/C++ 语言中的指针),所以只有一个对象的原始实例和对它的多个引用:

var A:Array = [1, 2];
var B:Array;

// Now we pass the reference to the A.
B = A;
A[0] = 2;

trace(A); // output: 2,2
trace(B); // output: 2,2

为了复制对象数据,您需要一些了解。正如DodgerThud提到的,有深拷贝和浅拷贝术语。简单地说,拷贝创建顶级容器的克隆,同时按原样复制更深层次。深层副本将所有内容克隆到底部,因此无论您对另一个副本做什么,其中一个副本都不会受到任何影响。

浅拷贝Array

var A:Array = [1,2,[3]];
var B:Array;

// Make a shallow copy.
B = A.slice();

// Lets change the original and see.
A[0] = 2;
A[1] = 3;
A[2][0] = 4;

trace(A); // output: 2,3,4
trace(B); // output: 1,2,4

因此, A 和 B 是不同的Array,但它们的最后一个元素指的是同一个Array

浅拷贝对象:

var A:Object = {a:1,b:2,c:[3]};
var B:Object;

// Make a shallow copy.
B = new Object;

// Iterate over keys in A.
for (var aKey:String in A)
{
    // Copy members of A one by one.
    B[aKey] = A[aKey];
}

// Let's change the original and see.
A.a = 2;
A.b = 3;
A.c[0] = 4;

trace(A.a, A.b, A.c); // output: 2 3 4
trace(B.a, B.b, B.c); // output: 1 2 4

然后,深拷贝。通常,您递归地遍历顶级对象及其所有后代,以确保每条数据都作为副本而不是对原始数据的引用。同时,您要注意重复条目和循环引用。

然而(幸运的是)在 AS3 中有一些捷径。您可以通过ByteArray进行深度复制。这将(测试并确认)处理重复和循环引用就好了:

function deepCopy(source:*):*
{
    var BA:ByteArray = new ByteArray;

    BA.writeObject(source);
    BA.position = 0;

    var result:* = BA.readObject();

    BA.clear();

    return result;
}

var A:Array = [1, 2, [3]];
var B:Array = deepCopy(A);

// Let's change the original and see.
A[0] = 2;
A[1] = 3;
A[2][0] = 4;

trace(A); // output: 2,3,4
trace(B); // output: 1,2,3

不确定,如果它会以任何方式更快,更好,或更优化,但仍然是另一种方式:

function deepCopy(source:*):*
{
    return JSON.parse(JSON.stringify(source));
}

对两者都有一些见解。

JSON深拷贝:

  • 重复:否(将它们克隆为不同的对象)
  • 循环引用:否(运行时错误)
  • 自定义类:没有
  • 支持的数据类型:int、uint、Number、Boolean、String、Object、Array

ByteArray深拷贝:

  • 重复:是
  • 循环引用:是
  • 自定义类:通过registerClassAlias方法
  • 支持的数据类型:int、uint、Number、Boolean、String、Object、Array、ByteArray

这是我自己的deepCopy版本:

private const SIMPLE:Object =
{
    "number":true,
    "string":true,
    "boolean":true,
    "undefined":true
};

private const XNODE:String = getQualifiedClassName(XML);
private const XLIST:String = getQualifiedClassName(XMLList);
private const ARRAY:String = getQualifiedClassName(Array);
private const OBJECT:String = getQualifiedClassName(Object);
private const BYTES:String = getQualifiedClassName(ByteArray);

private var lock:Dictionary;

private function deepCopy(source:*):*
{
    // Handle primitive data.
    if (source == null) return source;
    if (source is Class) return source;
    if (SIMPLE[typeof(source)]) return source;

    var result:*;
    var aLock:Boolean;
    var aQname:String;

    if (!lock)
    {
        // If we're here, then we're at the top level
        // so we should devise cache for handling
        // duplicates and circular references.
        lock = new Dictionary;
        aLock = true;
    }

    // If it is cached, then it is either
    // duplicate or circular reference.
    if (lock[source]) return lock[source];

    aQname = getQualifiedClassName(source);

    if (aQname == BYTES)
    {
        var aBytes:ByteArray;

        aBytes = new ByteArray;
        aBytes.writeBytes(source, 0, source.length);

        result = aBytes;
        lock[source] = result;
    }
    else if (aQname == ARRAY)
    {
        var aRay:Array;

        aRay = new Array;
        aRay.length = source.length;

        result = aRay;
        lock[source] = result;

        // Copy the elements of the source Array one by one.
        for (var i:int = 0; i < aRay.length; i++)
        {
            aRay[i] = deepCopy(source[i]);
        }
    }
    else if (aQname == OBJECT)
    {
        var aRes:Object;

        aRes = new Object;

        result = aRes;
        lock[source] = result;

        // Copy the members of the source Object one by one.
        for (var aKey:String in source)
        {
            aRes[aKey] = deepCopy(source[aKey]);
        }
    }
    else if ((aQname == XNODE) || (aQname == XLIST))
    {
        // This one is tricky. The object to clone might
        // have a reference to some descendant node of some
        // big XML. There could be several references to
        // different sub-nodes either. Probably you should
        // not rely on this method to clone XML data unless
        // you are totally aware of what you are doing.

        result = source.copy();
        lock[source] = result;
    }
    else
    {
        // If we're here, that means that source holds
        // a reference to some class instance. You should
        // define here your own ways to handle them.

        result = source;
    }

    if (aLock)
    {
        // If we're here, then we're at the top level
        // so we should do some clean-up before we leave.

        for (var aRef:* in lock)
        {
            delete lock[aRef];
        }

        lock = null;
    }

    return result;
}

自定义深拷贝:

  • 重复:是
  • 循环引用:是
  • 自定义类:您应该定义自己的处理规则
  • 支持的数据类型:int、uint、Number、Boolean、String、Object、Array、ByteArray、XML(有限)、类构造函数

推荐阅读