我是clojure的新手(以及函数式编程),我试图做一些基本的问题。我试图在没有递归的情况下找到序列中的第n个元素。
类似
(my-nth '(1 2 3 4) 2) => 3
我很难在列表中循环并在找到第n个元素时返回。我尝试了很多不同的方法,而我最终得到的代码是
(defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (pop tmp-list)))))
这给了我一个例外,说“不能从空列表中弹出”
我不需要代码,但如果有人能指出我正确的方向,它会真的有用!
答案 0 :(得分:3)
您正在使用函数pop
,它对不同的数据结构具有不同的行为。
user> (pop '(0 1 2 3 4))
(1 2 3 4)
user> (pop [0 1 2 3 4])
[0 1 2 3]
user> (pop (map identity '(0 1 2 3 4)))
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:640)
此外,您正在调用pop
与first
的来电。如果是迭代,请使用peek
/ pop
或first
/ rest
作为对,将两者混合会导致意外结果。 first
/ rest
是最低的共同标准,如果您想要对各种顺序类型进行推广,请使用它们,如果可以的话,它们会强制序列生效。
user> (first "hello")
\h
user> (first #{0 1 2 3 4})
0
user> (first {:a 0 :b 1 :c 2})
[:c 2]
使用您的功能,将pop
替换为rest
,我们会得到预期的结果:
user> (defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (rest tmp-list)))))
#'user/sdsu-nth
user> (sdsu-nth (map identity '(0 1 2 3 4)) 2)
2
user> (sdsu-nth [0 1 2 3 4] 2)
2
user> (sdsu-nth '(0 1 2 3 4) 2)
2
user> (sdsu-nth "01234" 2)
\2
答案 1 :(得分:2)
您真正想要做的是使用内置的nth
函数,因为它完全符合您的要求:
http://clojuredocs.org/clojure_core/clojure.core/nth
然而,既然你正在学习这仍然是一个很好的练习。你的代码实际上适合我。确保你给它一个列表而不是矢量 - pop用向量做了不同的事情(它返回的矢量没有最后一个项而不是第一个 - see here)。
答案 2 :(得分:2)
将列表作为nth
,最多可以使用(fn [list_nums n] (last (take (inc n) list_nums)))
,然后返回最后一个#(last (take (inc %2) %1))
元素。
(= (#(last (take (inc %2) %1)) '(4 5 6 7) 2) 6) ;; => true
或者:
package com.example.brian.inventoryapp;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static android.R.layout.simple_list_item_1;
public class MainActivity extends AppCompatActivity {
public static final int CREATE_REQUEST = 1;
private Button addButton;
private ListView itemListView;
private ArrayList<String> arrayList;
private ArrayAdapter<String> arrayAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
itemListView = (ListView) findViewById(R.id.itemListView);
addButton = (Button) findViewById(R.id.addButton);
arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arrayList);
itemListView.setAdapter(arrayAdapter);
addButton = (Button) findViewById(R.id.addButton);
addButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, CreateActivity.class);
startActivityForResult(intent, CREATE_REQUEST);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CREATE_REQUEST) {
if (resultCode == RESULT_OK) {
String item = data.getStringExtra("data");
arrayList.add(item);
arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arrayList);
itemListView.setAdapter(arrayAdapter);
}
}
}
}
证明:
createButton
答案 3 :(得分:1)
如果提供的索引不等于或大于序列的长度(您已实现零索引nth
),则您的代码适用于列表。如果tmp-list
在cnt
变为零之前变为空,则会出现此错误。
使用矢量不能很好地工作:
user> (sdsu-nth [1 2 3 4] 2)
;; => 1
user> (sdsu-nth [10 2 3 4] 2)
;; => 10
它似乎为每个提供的索引返回0
元素。正如noisesmith注意到它发生的原因是pop
因为内部结构而对矢量的工作方式不同。对于向量pop
,将从结尾删除元素,然后first
返回任何向量的第一个值。
如何修复:使用rest
代替pop
,以便在应用于列表和向量时消除函数行为的差异。
答案 4 :(得分:1)
(fn [xs n]
(if (= n 0)
(first xs)
(recur (rest xs) (dec n))))
答案 5 :(得分:0)
我想到这样做的另一种方式是让它真正非递归(即没有for / recur)是
(defn sdsu-nth
[input-list n]
(if (zero? (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (>= n (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (neg? n)
(throw (Exception. "IndexOutOfBoundsException"))
(last (take (+ n 1) input-list))))))