【问题标题】:How to return a 2D String如何返回二维字符串
【发布时间】:2018-06-10 00:34:58
【问题描述】:

我不完全了解如何返回 2D 对象。所以我写了一个方法,它接受一个文档的输入,我必须返回一个列表,其中包含所有唯一单词及其出现次数,按出现次数降序排序。要求我无法控制将其作为二维字符串数组返回。

这就是我目前所拥有的:

static String[][] wordCountEngine(String document) {
    // your code goes here
    if (document == null || document.length() == 0)
        return null;

    Map<String, String> map = new HashMap<>();
    String[] allWords = document.toLowerCase().split("[^a-zA-Z]+");

    for (String s : allWords) {
        if (map.containsKey(s)) {

            int newVersion = (Integer.parseInt(map.get(s).substring(1, map.get(s).length())) + 1);
            String sb = Integer.toString(newVersion);
            map.put(s, sb);
        } else {
            map.put(s, "1");
        }
    }

    String[][] array = new String[map.size()][2];
    int count = 0;
    for (Map.Entry<String, String> entry : map.entrySet()) {
        array[count][0] = entry.getKey();
        array[count][1] = entry.getValue();
        count++;
    }

    return array;
}

我正在尝试使用 HashMap 来存储单词及其出现的次数。将表中的键->值对存储到String [] []中的最佳方法是什么。 如果输入是:

input:  document = "Practice makes perfect. you'll only
                get Perfect by practice. just practice!"

输出应该是:

output: [ ["practice", "3"], ["perfect", "2"],
      ["by", "1"], ["get", "1"], ["just", "1"],
      ["makes", "1"], ["only", "1"], ["youll", "1"]  ]

如何将这样的数据存储在二维数组中?

【问题讨论】:

  • 这是一个糟糕的主意,因为您使用字符串来表示数字数据。为什么不简单地返回一个 Map&lt;String, Integer&gt; 或创建一个包含 String 和 int 值的自定义类型?
  • @HovercraftFullOfEels 是的,我认为你是对的。我最好创建自己的数据类型来存储值。这是一个编码挑战,所以我必须返回一个 String[][]。不是我的选择。无论如何,谢谢。
  • 哼,好吧,我不赞成他们的要求。
  • “这是一个编码挑战,所以我必须返回一个 String[][]。不是我的选择。” 编码挑战不是学习的最佳方式 Java。你最好先通过官方教程:docs.oracle.com/javase/tutorial
  • @TimothyTruckle 谢谢,我会记住的。

标签: java sorting multidimensional-array hashmap


【解决方案1】:

这是我对 Pramp 问题的解决方案,尽管在 C# 中我认为这是相同的想法

   [TestMethod]
        public void PrampWordCountEngineTest()
        {

            string document = "Practice makes perfect. you'll only get Perfect by practice. just practice!";
            string[,] result = WordCountEngine(document);
            string[,] expected =
            {
                {"practice", "3"}, {"perfect", "2"},
                {"makes", "1"}, {"youll", "1"}, {"only", "1"},
                {"get", "1"}, {"by", "1"}, {"just", "1"}
            };
            CollectionAssert.AreEqual(expected,result);

        }
        public string[,] WordCountEngine(string document)
        {
            Dictionary<string, int> wordMap = new Dictionary<string, int>();
            string[] wordList = document.Split(' ');
            int largestCount = 0;
            foreach (string word in wordList)
            {
                string lowerWord = word.ToLower(); // can't assing to the same variable

                //remove special/punctuation characters
                var sb = new StringBuilder();
                foreach (var c in lowerWord)
                {
                    if (c >= 'a' && c <= 'z')
                    {
                        sb.Append(c);
                    }
                }
                string cleanWord = sb.ToString();
                if (cleanWord.Length < 1)
                {
                    continue;
                }
                int count = 0;
                if (wordMap.ContainsKey(cleanWord))
                {
                    count = wordMap[cleanWord];
                    count++;
                }
                else
                {
                    count = 1;
                }
                if (count > largestCount)
                {
                    largestCount = count;
                }
                wordMap[cleanWord] = count;
            }

            // we have a list of all of the words in the same length in a given cell of the big list
            List<List<string>> counterList = new List<List<string>>();
            for (int i = 0; i < largestCount + 1; i++)
            {
                counterList.Add(new List<string>());
            }
            foreach (var word in wordMap.Keys)
            {
                int counter = wordMap[word];
                counterList[counter].Add(word);
            }

            string[,] result = new string[wordMap.Keys.Count,2];
            int key = 0;
            //foreach list of words with the same length we insert the count of that word into the 2D array
            for (var index = counterList.Count-1; index > 0; index--)
            {
                var list = counterList[index];
                List<string> wordListCounter = list;
                if (wordListCounter == null)
                {
                    continue;
                }
                foreach (var word in wordListCounter)
                {
                    result[key, 0] = word;
                    result[key, 1] = index.ToString();
                    key++;
                }
            }
            return result;
        }

【讨论】:

    【解决方案2】:

    仅仅因为您需要返回特定类型的数据结构并不意味着您需要在方法中创建类似类型的映射。没有什么能阻止您使用Map&lt;String, Integer&gt;,然后将其转换为String[][]

    这里是不使用 Java8 流的代码:

    static String[][] wordCountEngine(String document) {
            // your code goes here
            if (document == null || document.length() == 0)
                return null;
    
            Map<String, Integer> map = new HashMap<>();
    
            for ( String s : document.toLowerCase().split("[^a-zA-Z]+") ){
                Integer c = map.get(s);
                map.put(s, c != null ? c + 1: 1);
            }
    
            String[][] result = new String[ map.size() ][ 2 ];
    
            int count = 0;
            for ( Map.Entry<String, Integer> e : map.entrySet() ){
                result[count][0] = e.getKey();
                result[count][1] = e.getValue().toString();
                count += 1;
            }
    
            return result;
        }  
    

    为了好玩,还有一个 Java8 版本:

    static String[][] wordCountEngine(String document) {
        // your code goes here
        if (document == null || document.length() == 0)
            return null;
    
        return Arrays
        //convert words into map with word and count
        .stream( document.toLowerCase().split("[^a-zA-Z]+") )
        .collect( Collectors.groupingBy( s -> s, Collectors.summingInt(s -> 1) ) )
        //convert the above map to String[][]
        .entrySet()
        .stream().map( (e) -> new String[]{ e.getKey(), e.getValue().toString() } )
        .toArray( String[][]::new  );
    
    }
    

    【讨论】:

      【解决方案3】:

      String[][] 只是这个任务的错误数据结构。 您应该在方法运行期间使用 Map&lt;String, Integer&gt; map 而不是 &lt;String, String&gt; 并简单地返回该映射。

      这有多种原因:

      • 您将整数存储为字符串,甚至通过再次将字符串解析为整数来进行计算,计算然后再解析 - 坏主意。
      • 返回的数组不保证维度,没有办法强制每个子数组只有两个元素。

      关于您的评论的注意事项:如果(出于某种原因)您需要将地图转换为String[][],您当然可以这样做,但转换逻辑应该与生成地图本身的代码分开。这样wordCountEngine 的代码就保持干净且易于维护。

      【讨论】:

      • 过度使用字符串来表示非文本数据是一种设计味道。这是合适的解决方案。
      • 这是一个编码挑战,他们想要一个 String[][] 作为返回值。不过还是谢谢。
      • @RockySingh 我添加了关于这种情况的注释。
      • @luk2302 谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      • 2016-04-04
      • 2011-01-24
      • 1970-01-01
      相关资源
      最近更新 更多