从字符串[,]中删除空值

时间:2015-05-07 14:19:06

标签: c# arrays string multidimensional-array

我在c#中定义了一个字符串数组

string[,] options = new string[100,3];

在整个代码中,它会填充数据,但并不总是填充。

因此,如果我有80个部分填充,20个部分未填充。 20个部分中包含空值或最后有60个空值。是否有一种简单的方法来调整数组的大小,以便在填充数组后,数组与

相同
String[,] options = new string[80,3];

必须根据它找到的第一组3个零点的位置来调整大小。

如果这是一个锯齿状阵列,我会做的

options = options.Where(x => x != null).ToArray();

4 个答案:

答案 0 :(得分:7)

这个方法很长,因为它必须检查每一行两次......

private static final long serialVersionUID = 1L;

@SuppressWarnings("unchecked")
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

    resp.setContentType("application/json");
    String action = req.getParameter("action");

    try{
    switch(action){
    case "login": 
        AuthenticationActionsHandler authentication = new AuthenticationActionsHandler();
        sendResponse(resp, authentication.logIn(req) );
    break;
    case "registration":
        authentication = new AuthenticationActionsHandler();
        sendResponse(resp, authentication.registration(req) );
    break;
    case "getName": 
        if((Integer) req.getSession().getAttribute("Id") != null){
            UserActionsHandler user = new UserActionsHandler();
            sendResponse(resp, user.getName(req) );
        }
    break;
    case "logOut":
        authentication = new AuthenticationActionsHandler();
        sendResponse(resp, authentication.logOut(req) );            
    break;
    case "search": 
        ActionsHandler searchAction = new ActionsHandler();
        sendResponse(resp, searchAction.search(req) );
    break;
    case "saveRequest":
        ActionsHandler saveRequestAction = new ActionsHandler();
        sendResponse(resp, saveRequestAction.saveRequest(req) );
    break;
    case "showRequestedBooks":
        HttpSession session = req.getSession(true);
        Integer userId = (Integer)session.getAttribute("Id");
        if(userId == null){
            JSONObject result = new JSONObject();
            result.put("authentication", false);
            sendResponse(resp, result);
        } else{
            ActionsHandler showRequestedBooks = new ActionsHandler();
            sendResponse(resp, showRequestedBooks.showRequestedItems(req) );
        }
    break;

    }
}catch(MissingParameterException e){
        sendErrorResponse(resp, e.getMissingParams());
}
}

public void sendResponse(HttpServletResponse resp, JSONArray resultJson ){
    PrintWriter out;
    try {
        out = resp.getWriter();
        out.println(resultJson);
    } catch (IOException e) {
        e.printStackTrace();
    }
}





$("#login").click(function(){
var hashPassword = hex_md5($("#password").val());
var requestData = {
        username: $('#username').val(),
        password: hashPassword,
        action: "login",
};
$.ajax({
    type : "POST",
    url : "/Library/dispatcher",
    data : requestData,
 }).done(
         function(responseData){
             if(responseData.error){
                 console.log(responseData.error);
                 $('#unsuccess').show();
             }
             else{
                 if(responseData.success){
                    // window.location.href = "/Library/search.html";
                     window.location.href = "/WEB-INF/search.html";
                 }
                 else{
                     $('#unsuccess').show();
                 }
             }
        });
});

使用它像:

public static string[,] RemoveEmptyRows(string[,] strs)
{
    int length1 = strs.GetLength(0);
    int length2 = strs.GetLength(1);

    // First we count the non-emtpy rows
    int nonEmpty = 0;

    for (int i = 0; i < length1; i++)
    {
        for (int j = 0; j < length2; j++)
        {
            if (strs[i, j] != null)
            {
                nonEmpty++;
                break;
            }
        }
    }

    // Then we create an array of the right size
    string[,] strs2 = new string[nonEmpty, length2];

    for (int i1 = 0, i2 = 0; i2 < nonEmpty; i1++)
    {
        for (int j = 0; j < length2; j++)
        {
            if (strs[i1, j] != null)
            {
                // If the i1 row is not empty, we copy it
                for (int k = 0; k < length2; k++)
                {
                    strs2[i2, k] = strs[i1, k];
                }

                i2++;
                break;
            }
        }
    }

    return strs2;
}

根据阿列克谢的建议,还有另一种方法:

string[,] options = new string[100, 3];
options[1, 0] = "Foo";
options[3, 1] = "Bar";
options[90, 2] = "fiz";
options = RemoveEmptyRows(options);

这一点,在权衡记忆与时间的关系中,选择时间。它可能更快,因为它不必检查每一行两次,但它使用更多的内存,因为它将某些非空索引列入。

答案 1 :(得分:0)

我去了所有行,直到找到一个包含所有空值的行:

需要进行一些清理,并且显然会删除在第一个所有空行之后出现的非空行。这里的要求不太清楚

编辑:刚看到澄清要求删除所有空行的评论 - 我已经调整了以下内容以避免downvotes但是已经接受了更全面的答案(并且效率更高):)< / p>

void Main()
{
    string[,] options = new string[100,3];

    options[0,0] = "bleb";
    options[1,1] = "bleb";
    options[2,0] = "bleb";
    options[2,1] = "bleb";
    options[3,2] = "bleb";
    options[4,1] = "bleb";

    string[,] trimmed = TrimNullRows(options);

    Console.WriteLine(trimmed);
}

public string[,] TrimNullRows(string[,] options) 
{
    IList<string[]> nonNullRows = new List<string[]>();
    for (int x = 0; x < options.GetLength(0); x++) 
    {
        bool allNull = true;

        var row = new string[options.GetLength(1)];

        for (int y = 0; y < options.GetLength(1); y++) 
        {
            row[y] = options[x,y];
            allNull &= options[x,y] == null;
        }


        if (!allNull) 
        {
            nonNullRows.Add(row);
        }
    }

    var optionsTrimmed = new string[nonNullRows.Count, options.GetLength(1)];

    for (int i=0;i<nonNullRows.Count;i++)
    {
        for (int j=0;j<options.GetLength(1);j++)
        {
            optionsTrimmed[i, j] = nonNullRows[i][j];
        }
    }


    return optionsTrimmed;
}

答案 2 :(得分:0)

linq的另一个变种

static string[,] RemoveNotNullRow(string[,] o)
{
    var rowLen = o.GetLength(1);
    var notNullRowIndex = (from oo in o.Cast<string>().Select((x, idx) => new { idx, x })
                group oo.x by oo.idx / rowLen into g
                where g.Any(f => f != null)
                select g.Key).ToArray();

    var res = new string[notNullRowIndex.Length, rowLen];

    for (int i = 0; i < notNullRowIndex.Length; i++)
    {
        Array.Copy(o, notNullRowIndex[i] * rowLen, res, i * rowLen, rowLen);
    }
    return res;
}

答案 3 :(得分:0)

您还可以获得一些帮助,以便在锯齿状和多维表示之间进行转换。当然,这非常愚蠢,但是对于像你所展示的那些小的数组(以及非常稀疏的数组),它会很好。

void Main()
{
    string[,] options = new string[100,3];

    options[3, 1] = "Hi";
    options[5, 0] = "Dan";

    var results = 
        options
            .JagIt()
            .Where(i => i.Any(j => j != null))
            .UnjagIt();

    results.Dump();
}

static class Extensions
{
    public static IEnumerable<IEnumerable<T>> JagIt<T>(this T[,] array)
    {
        for (var i = 0; i < array.GetLength(0); i++)
            yield return GetRow(array, i);
    }

    public static IEnumerable<T> GetRow<T>(this T[,] array, int rowIndex)
    {
        for (var j = 0; j < array.GetLength(1); j++)
            yield return array[rowIndex, j];
    }

    public static T[,] UnjagIt<T>(this IEnumerable<IEnumerable<T>> jagged)
    {
        var rows = jagged.Count();
        if (rows == 0) return new T[0, 0];

        var columns = jagged.Max(i => i.Count());

        var array = new T[rows, columns];

        var row = 0;
        var column = 0;

        foreach (var r in jagged)
        {
          column = 0;

          foreach (var c in r)
          {
            array[row, column++] = c;
          }

          row++;
        }

        return array;
    }
}

JagIt方法当然非常简单 - 我们只是迭代行,yield个别项目。这给了我们一个可枚举的枚举,我们可以很容易地在LINQ中使用它们。如果需要,您当然可以将它们转换为数组(例如,Select(i => i.ToArray()).ToArray())。

UnjagIt方法更有说服力,因为我们需要先创建具有正确尺寸的目标数组。并且没有unyield指令来简化:D

当然,这是非常低效的,但这不一定是个问题。例如,你可以通过保持内部可枚举为array来保存自己的一些迭代 - 这将节省我们必须迭代所有内部项。

我主要将此作为内存便宜,CPU密集型替代@xanatos内存密集型,CPU便宜(相对)。

当然,主要的好处是它可以用来将任何多维数组视为锯齿状数组,然后再将它们转换回来。一般解决方案通常不是最有效的:D